mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #17474 from benpicco/nanocoap-suit
sys/net/nanocoap: introduce `nanocoap_sock_*()`, use in suit/transport/coap
This commit is contained in:
commit
bbfa69153e
@ -590,6 +590,7 @@ endif
|
||||
|
||||
ifneq (,$(filter nanocoap_sock,$(USEMODULE)))
|
||||
USEMODULE += sock_udp
|
||||
USEMODULE += sock_util
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nanocoap_%,$(USEMODULE)))
|
||||
|
@ -183,16 +183,16 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Timeout in seconds for a response to a confirmable request
|
||||
* @brief Timeout in milliseconds for a response to a confirmable request
|
||||
*
|
||||
* This value is for the response to the *initial* confirmable message. The
|
||||
* timeout doubles for subsequent retries. To avoid synchronization of resends
|
||||
* across hosts, the actual timeout is chosen randomly between
|
||||
* @ref CONFIG_COAP_ACK_TIMEOUT and
|
||||
* (@ref CONFIG_COAP_ACK_TIMEOUT * @ref CONFIG_COAP_RANDOM_FACTOR_1000 / 1000).
|
||||
* @ref CONFIG_COAP_ACK_TIMEOUT_MS and
|
||||
* (@ref CONFIG_COAP_ACK_TIMEOUT_MS * @ref CONFIG_COAP_RANDOM_FACTOR_1000 / 1000).
|
||||
*/
|
||||
#ifndef CONFIG_COAP_ACK_TIMEOUT
|
||||
#define CONFIG_COAP_ACK_TIMEOUT (2U)
|
||||
#ifndef CONFIG_COAP_ACK_TIMEOUT_MS
|
||||
#define CONFIG_COAP_ACK_TIMEOUT_MS (2000U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -202,7 +202,7 @@ extern "C" {
|
||||
* ([RFC 7252, section 4.2](https://tools.ietf.org/html/rfc7252#section-4.2))
|
||||
* multiplied by 1000, to avoid floating point arithmetic.
|
||||
*
|
||||
* See @ref CONFIG_COAP_ACK_TIMEOUT
|
||||
* See @ref CONFIG_COAP_ACK_TIMEOUT_MS
|
||||
*/
|
||||
#ifndef CONFIG_COAP_RANDOM_FACTOR_1000
|
||||
#define CONFIG_COAP_RANDOM_FACTOR_1000 (1500)
|
||||
@ -233,6 +233,19 @@ extern "C" {
|
||||
#define COAP_BLOCKWISE_SZX_MAX (7)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Coap block-wise-transfer size SZX
|
||||
*/
|
||||
typedef enum {
|
||||
COAP_BLOCKSIZE_16 = 0,
|
||||
COAP_BLOCKSIZE_32,
|
||||
COAP_BLOCKSIZE_64,
|
||||
COAP_BLOCKSIZE_128,
|
||||
COAP_BLOCKSIZE_256,
|
||||
COAP_BLOCKSIZE_512,
|
||||
COAP_BLOCKSIZE_1024,
|
||||
} coap_blksize_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -531,7 +531,7 @@ extern "C" {
|
||||
* In normal operations the timeout between retransmissions doubles. When
|
||||
* CONFIG_GCOAP_NO_RETRANS_BACKOFF is defined this doubling does not happen.
|
||||
*
|
||||
* @see CONFIG_COAP_ACK_TIMEOUT
|
||||
* @see CONFIG_COAP_ACK_TIMEOUT_MS
|
||||
*/
|
||||
#define CONFIG_GCOAP_NO_RETRANS_BACKOFF
|
||||
#endif
|
||||
@ -702,7 +702,7 @@ typedef struct gcoap_listener gcoap_listener_t;
|
||||
*/
|
||||
typedef int (*gcoap_request_matcher_t)(gcoap_listener_t *listener,
|
||||
const coap_resource_t **resource,
|
||||
const coap_pkt_t *pdu);
|
||||
coap_pkt_t *pdu);
|
||||
|
||||
/**
|
||||
* @brief A modular collection of resources for a server
|
||||
|
@ -86,6 +86,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef RIOT_VERSION
|
||||
#include "bitfield.h"
|
||||
#include "byteorder.h"
|
||||
#include "net/coap.h"
|
||||
#else
|
||||
@ -150,6 +151,21 @@ extern "C" {
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Maximum length of a CoAP header for a blockwise message
|
||||
*/
|
||||
#ifndef CONFIG_NANOCOAP_BLOCK_HEADER_MAX
|
||||
#define CONFIG_NANOCOAP_BLOCK_HEADER_MAX (64)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Work buffer size for blockwise operation
|
||||
*
|
||||
* @param[in] blksize CoAP blocksize
|
||||
*/
|
||||
#define NANOCOAP_BLOCKWISE_BUF(blksize) (CONFIG_NANOCOAP_BLOCK_HEADER_MAX \
|
||||
+ (0x1 << (blksize + 4)))
|
||||
|
||||
/**
|
||||
* @name coap_opt_finish() flag parameter values
|
||||
*
|
||||
@ -189,6 +205,7 @@ typedef struct {
|
||||
uint16_t payload_len; /**< length of payload */
|
||||
uint16_t options_len; /**< length of options array */
|
||||
coap_optpos_t options[CONFIG_NANOCOAP_NOPTS_MAX]; /**< option offset array */
|
||||
BITFIELD(opt_crit, CONFIG_NANOCOAP_NOPTS_MAX); /**< unhandled critical option */
|
||||
#ifdef MODULE_GCOAP
|
||||
uint32_t observe_value; /**< observe value */
|
||||
#endif
|
||||
@ -210,6 +227,20 @@ typedef struct {
|
||||
*/
|
||||
typedef ssize_t (*coap_handler_t)(coap_pkt_t *pkt, uint8_t *buf, size_t len, void *context);
|
||||
|
||||
/**
|
||||
* @brief Coap blockwise request callback descriptor
|
||||
*
|
||||
* @param[in] arg Pointer to be passed as arguments to the callback
|
||||
* @param[in] offset Offset of received data
|
||||
* @param[in] buf Pointer to the received data
|
||||
* @param[in] len Length of the received data
|
||||
* @param[in] more -1 for no option, 0 for last block, 1 for more blocks
|
||||
*
|
||||
* @returns 0 on success
|
||||
* @returns -1 on error
|
||||
*/
|
||||
typedef int (*coap_blockwise_cb_t)(void *arg, size_t offset, uint8_t *buf, size_t len, int more);
|
||||
|
||||
/**
|
||||
* @brief Method flag type
|
||||
*
|
||||
@ -433,8 +464,30 @@ static inline void coap_hdr_set_type(coap_hdr_t *hdr, unsigned type)
|
||||
* @name Functions -- Options Read
|
||||
*
|
||||
* Read options from a parsed packet.
|
||||
*
|
||||
* Packets accessed through @ref coap_find_option or any of the `coap_opt_get_*` functions
|
||||
* track their access in bit field created at parsing time to enable checking for critical
|
||||
* options in @ref coap_has_unprocessed_critical_options.
|
||||
* These functions thus have a side effect, and code that calls them on critical options
|
||||
* needs to ensure that failure to process the accessed option is propagated into failure
|
||||
* to process the message.
|
||||
* For example, a server helper that tries to read the If-None-Match option (which is critical)
|
||||
* and finds it to be longer than it can process must not return as if no If-None-Match option
|
||||
* was present, as it has already triggered the side effect of marking the option as processed.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* @brief Get pointer to an option field by type
|
||||
*
|
||||
* @param[in] pkt packet to work on
|
||||
* @param[in] opt_num the option number to search for
|
||||
*
|
||||
* @returns pointer to the option data
|
||||
* NULL if option number was not found
|
||||
*/
|
||||
uint8_t *coap_find_option(coap_pkt_t *pkt, unsigned opt_num);
|
||||
|
||||
/**
|
||||
* @brief Get content type from packet
|
||||
*
|
||||
@ -457,7 +510,7 @@ unsigned coap_get_content_type(coap_pkt_t *pkt);
|
||||
* @return -ENOSPC if option length is greater than 4 octets
|
||||
* @return -EBADMSG if option value is invalid
|
||||
*/
|
||||
int coap_opt_get_uint(const coap_pkt_t *pkt, uint16_t optnum, uint32_t *value);
|
||||
int coap_opt_get_uint(coap_pkt_t *pkt, uint16_t optnum, uint32_t *value);
|
||||
|
||||
/**
|
||||
* @brief Read a full option as null terminated string into the target buffer
|
||||
@ -476,7 +529,7 @@ int coap_opt_get_uint(const coap_pkt_t *pkt, uint16_t optnum, uint32_t *value);
|
||||
* @return -ENOSPC if the complete option does not fit into @p target
|
||||
* @return nr of bytes written to @p target (including '\0')
|
||||
*/
|
||||
ssize_t coap_opt_get_string(const coap_pkt_t *pkt, uint16_t optnum,
|
||||
ssize_t coap_opt_get_string(coap_pkt_t *pkt, uint16_t optnum,
|
||||
uint8_t *target, size_t max_len, char separator);
|
||||
|
||||
/**
|
||||
@ -494,7 +547,7 @@ ssize_t coap_opt_get_string(const coap_pkt_t *pkt, uint16_t optnum,
|
||||
* @returns -ENOSPC if URI option is larger than @p max_len
|
||||
* @returns nr of bytes written to @p target (including '\0')
|
||||
*/
|
||||
static inline ssize_t coap_get_location_path(const coap_pkt_t *pkt,
|
||||
static inline ssize_t coap_get_location_path(coap_pkt_t *pkt,
|
||||
uint8_t *target, size_t max_len)
|
||||
{
|
||||
return coap_opt_get_string(pkt, COAP_OPT_LOCATION_PATH,
|
||||
@ -516,7 +569,7 @@ static inline ssize_t coap_get_location_path(const coap_pkt_t *pkt,
|
||||
* @returns -ENOSPC if URI option is larger than @p max_len
|
||||
* @returns nr of bytes written to @p target (including '\0')
|
||||
*/
|
||||
static inline ssize_t coap_get_location_query(const coap_pkt_t *pkt,
|
||||
static inline ssize_t coap_get_location_query(coap_pkt_t *pkt,
|
||||
uint8_t *target, size_t max_len)
|
||||
{
|
||||
return coap_opt_get_string(pkt, COAP_OPT_LOCATION_QUERY,
|
||||
@ -537,7 +590,7 @@ static inline ssize_t coap_get_location_query(const coap_pkt_t *pkt,
|
||||
* @returns -ENOSPC if URI option is larger than CONFIG_NANOCOAP_URI_MAX
|
||||
* @returns nr of bytes written to @p target (including '\0')
|
||||
*/
|
||||
static inline ssize_t coap_get_uri_path(const coap_pkt_t *pkt, uint8_t *target)
|
||||
static inline ssize_t coap_get_uri_path(coap_pkt_t *pkt, uint8_t *target)
|
||||
{
|
||||
return coap_opt_get_string(pkt, COAP_OPT_URI_PATH, target,
|
||||
CONFIG_NANOCOAP_URI_MAX, '/');
|
||||
@ -557,7 +610,7 @@ static inline ssize_t coap_get_uri_path(const coap_pkt_t *pkt, uint8_t *target)
|
||||
* @returns -ENOSPC if URI option is larger than CONFIG_NANOCOAP_URI_MAX
|
||||
* @returns nr of bytes written to @p target (including '\0')
|
||||
*/
|
||||
static inline ssize_t coap_get_uri_query(const coap_pkt_t *pkt, uint8_t *target)
|
||||
static inline ssize_t coap_get_uri_query(coap_pkt_t *pkt, uint8_t *target)
|
||||
{
|
||||
return coap_opt_get_string(pkt, COAP_OPT_URI_QUERY, target,
|
||||
CONFIG_NANOCOAP_URI_MAX, '&');
|
||||
@ -611,7 +664,7 @@ ssize_t coap_opt_get_next(const coap_pkt_t *pkt, coap_optpos_t *opt,
|
||||
* @return -ENOENT if option not found
|
||||
* @return -EINVAL if option cannot be parsed
|
||||
*/
|
||||
ssize_t coap_opt_get_opaque(const coap_pkt_t *pkt, unsigned opt_num, uint8_t **value);
|
||||
ssize_t coap_opt_get_opaque(coap_pkt_t *pkt, unsigned opt_num, uint8_t **value);
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
@ -626,7 +679,7 @@ ssize_t coap_opt_get_opaque(const coap_pkt_t *pkt, unsigned opt_num, uint8_t **v
|
||||
* @return -ENOENT if Proxy-Uri option not found
|
||||
* @return -EINVAL if Proxy-Uri option cannot be parsed
|
||||
*/
|
||||
static inline ssize_t coap_get_proxy_uri(const coap_pkt_t *pkt, char **target)
|
||||
static inline ssize_t coap_get_proxy_uri(coap_pkt_t *pkt, char **target)
|
||||
{
|
||||
return coap_opt_get_opaque(pkt, COAP_OPT_PROXY_URI, (uint8_t **)target);
|
||||
}
|
||||
@ -831,6 +884,25 @@ static inline int coap_get_block2(coap_pkt_t *pkt, coap_block1_t *block)
|
||||
*/
|
||||
int coap_get_blockopt(coap_pkt_t *pkt, uint16_t option, uint32_t *blknum, unsigned *szx);
|
||||
|
||||
/**
|
||||
* @brief Check whether any of the packet's options that are critical
|
||||
*
|
||||
* (i.e must be understood by the receiver, indicated by a 1 in the option number's least
|
||||
* significant bit) were not accessed since the packet was parsed.
|
||||
*
|
||||
* Call this in a server on requests after all their option processing has happened,
|
||||
* and stop processing the request if it returns true, returning a 4.02 Bad Option response.
|
||||
*
|
||||
* Call this in a client when receiving a response before acting on it;
|
||||
* consider the response unprocessable if it returns true.
|
||||
*
|
||||
* @param[in] pkt pkt to work on
|
||||
*
|
||||
* @returns true if any of the options marked as critical at parse time have not been accessed.
|
||||
* @returns false if there are no critical options, or all have been accessed.
|
||||
*/
|
||||
bool coap_has_unprocessed_critical_options(const coap_pkt_t *pkt);
|
||||
|
||||
/**
|
||||
* @brief Helper to decode SZX value to size in bytes
|
||||
*
|
||||
|
@ -139,6 +139,12 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief nanocoap socket type
|
||||
*
|
||||
*/
|
||||
typedef sock_udp_t nanocoap_sock_t;
|
||||
|
||||
/**
|
||||
* @brief Start a nanocoap server instance
|
||||
*
|
||||
@ -153,10 +159,33 @@ extern "C" {
|
||||
*/
|
||||
int nanocoap_server(sock_udp_ep_t *local, uint8_t *buf, size_t bufsize);
|
||||
|
||||
/**
|
||||
* @brief Create a CoAP client socket
|
||||
*
|
||||
* @param[out] sock CoAP UDP socket
|
||||
* @param[in] local Local UDP endpoint, may be NULL
|
||||
* @param[in] remote remote UDP endpoint
|
||||
*
|
||||
* @returns 0 on success
|
||||
* @returns <0 on error
|
||||
*/
|
||||
int nanocoap_sock_connect(nanocoap_sock_t *sock, sock_udp_ep_t *local,
|
||||
sock_udp_ep_t *remote);
|
||||
|
||||
/**
|
||||
* @brief Close a CoAP client socket
|
||||
*
|
||||
* @param[in] sock CoAP UDP socket
|
||||
*/
|
||||
static inline void nanocoap_sock_close(nanocoap_sock_t *sock)
|
||||
{
|
||||
sock_udp_close(sock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Simple synchronous CoAP (confirmable) get
|
||||
*
|
||||
* @param[in] remote remote UDP endpoint
|
||||
* @param[in] sock socket to use for the request
|
||||
* @param[in] path remote path
|
||||
* @param[out] buf buffer to write response to
|
||||
* @param[in] len length of @p buffer
|
||||
@ -164,8 +193,66 @@ int nanocoap_server(sock_udp_ep_t *local, uint8_t *buf, size_t bufsize);
|
||||
* @returns length of response payload on success
|
||||
* @returns <0 on error
|
||||
*/
|
||||
ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, uint8_t *buf,
|
||||
size_t len);
|
||||
ssize_t nanocoap_sock_get(nanocoap_sock_t *sock, const char *path, void *buf,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* @brief Performs a blockwise coap get request on a socket.
|
||||
*
|
||||
* This function will fetch the content of the specified resource path via
|
||||
* block-wise-transfer. A coap_blockwise_cb_t will be called on each received
|
||||
* block.
|
||||
*
|
||||
* @param[in] sock socket to use for the request
|
||||
* @param[in] path pointer to source path
|
||||
* @param[in] blksize sender suggested SZX for the COAP block request
|
||||
* @param[in] work_buf Work buffer, must be `NANOCOAP_BLOCKWISE_BUF(blksize)` bytes
|
||||
* @param[in] callback callback to be executed on each received block
|
||||
* @param[in] arg optional function arguments
|
||||
*
|
||||
* @returns -EINVAL if an invalid url is provided
|
||||
* @returns -1 if failed to fetch the url content
|
||||
* @returns 0 on success
|
||||
*/
|
||||
int nanocoap_sock_get_blockwise(nanocoap_sock_t *sock, const char *path,
|
||||
coap_blksize_t blksize, void *work_buf,
|
||||
coap_blockwise_cb_t callback, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Performs a blockwise coap get request to the specified url.
|
||||
*
|
||||
* This function will fetch the content of the specified resource path via
|
||||
* block-wise-transfer. A coap_blockwise_cb_t will be called on each received
|
||||
* block.
|
||||
*
|
||||
* @param[in] url Absolute URL pointer to source path (i.e. not containing
|
||||
* a fragment identifier)
|
||||
* @param[in] blksize sender suggested SZX for the COAP block request
|
||||
* @param[in] work_buf Work buffer, must be `NANOCOAP_BLOCKWISE_BUF(blksize)` bytes
|
||||
* @param[in] callback callback to be executed on each received block
|
||||
* @param[in] arg optional function arguments
|
||||
*
|
||||
* @returns -EINVAL if an invalid url is provided
|
||||
* @returns -1 if failed to fetch the url content
|
||||
* @returns 0 on success
|
||||
*/
|
||||
int nanocoap_get_blockwise_url(const char *url,
|
||||
coap_blksize_t blksize, void *work_buf,
|
||||
coap_blockwise_cb_t callback, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Simple synchronous CoAP request
|
||||
*
|
||||
* @param[in] sock socket to use for the request
|
||||
* @param[in,out] pkt Packet struct containing the request. Is reused for
|
||||
* the response
|
||||
* @param[in] len Total length of the buffer associated with the
|
||||
* request
|
||||
*
|
||||
* @returns length of response on success
|
||||
* @returns <0 on error
|
||||
*/
|
||||
ssize_t nanocoap_sock_request(nanocoap_sock_t *sock, coap_pkt_t *pkt, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Simple synchronous CoAP request
|
||||
@ -183,6 +270,20 @@ ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, uint8_t *buf,
|
||||
ssize_t nanocoap_request(coap_pkt_t *pkt, sock_udp_ep_t *local,
|
||||
sock_udp_ep_t *remote, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Simple synchronous CoAP (confirmable) get
|
||||
*
|
||||
* @param[in] remote remote UDP endpoint
|
||||
* @param[in] path remote path
|
||||
* @param[out] buf buffer to write response to
|
||||
* @param[in] len length of @p buffer
|
||||
*
|
||||
* @returns length of response payload on success
|
||||
* @returns <0 on error
|
||||
*/
|
||||
ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, void *buf,
|
||||
size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -90,37 +90,11 @@ typedef const struct {
|
||||
const size_t resources_numof; /**< nr of entries in array */
|
||||
} coap_resource_subtree_t;
|
||||
|
||||
/**
|
||||
* @brief Coap blockwise request callback descriptor
|
||||
*
|
||||
* @param[in] arg Pointer to be passed as arguments to the callback
|
||||
* @param[in] offset Offset of received data
|
||||
* @param[in] buf Pointer to the received data
|
||||
* @param[in] len Length of the received data
|
||||
* @param[in] more -1 for no option, 0 for last block, 1 for more blocks
|
||||
*
|
||||
* @returns 0 on success
|
||||
* @returns -1 on error
|
||||
*/
|
||||
typedef int (*coap_blockwise_cb_t)(void *arg, size_t offset, uint8_t *buf, size_t len, int more);
|
||||
|
||||
/**
|
||||
* @brief Reference to the coap resource subtree
|
||||
*/
|
||||
extern const coap_resource_subtree_t coap_resource_subtree_suit;
|
||||
|
||||
/**
|
||||
* @brief Coap block-wise-transfer size SZX
|
||||
*/
|
||||
typedef enum {
|
||||
COAP_BLOCKSIZE_32 = 1,
|
||||
COAP_BLOCKSIZE_64,
|
||||
COAP_BLOCKSIZE_128,
|
||||
COAP_BLOCKSIZE_256,
|
||||
COAP_BLOCKSIZE_512,
|
||||
COAP_BLOCKSIZE_1024,
|
||||
} coap_blksize_t;
|
||||
|
||||
/**
|
||||
* @brief Coap block-wise-transfer size used for SUIT
|
||||
*/
|
||||
@ -128,26 +102,6 @@ typedef enum {
|
||||
#define CONFIG_SUIT_COAP_BLOCKSIZE COAP_BLOCKSIZE_64
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Performs a blockwise coap get request to the specified url.
|
||||
*
|
||||
* This function will fetch the content of the specified resource path via
|
||||
* block-wise-transfer. A coap_blockwise_cb_t will be called on each received
|
||||
* block.
|
||||
*
|
||||
* @param[in] url url pointer to source path
|
||||
* @param[in] blksize sender suggested SZX for the COAP block request
|
||||
* @param[in] callback callback to be executed on each received block
|
||||
* @param[in] arg optional function arguments
|
||||
*
|
||||
* @returns -EINVAL if an invalid url is provided
|
||||
* @returns -1 if failed to fetch the url content
|
||||
* @returns 0 on success
|
||||
*/
|
||||
int suit_coap_get_blockwise_url(const char *url,
|
||||
coap_blksize_t blksize,
|
||||
coap_blockwise_cb_t callback, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Trigger a SUIT udate
|
||||
*
|
||||
|
@ -18,15 +18,15 @@ menuconfig KCONFIG_COAP
|
||||
|
||||
if KCONFIG_COAP
|
||||
|
||||
config COAP_ACK_TIMEOUT
|
||||
int "Timeout in seconds for a response to a confirmable request"
|
||||
default 2
|
||||
config COAP_ACK_TIMEOUT_MS
|
||||
int "Timeout in milliseconds for a response to a confirmable request"
|
||||
default 2000
|
||||
help
|
||||
This value is for the response to the initial confirmable message. The
|
||||
timeout doubles for subsequent retries. To avoid synchronization of
|
||||
resends across hosts, the actual timeout is chosen randomly between
|
||||
@ref CONFIG_COAP_ACK_TIMEOUT and
|
||||
(@ref CONFIG_COAP_ACK_TIMEOUT * @ref CONFIG_COAP_RANDOM_FACTOR_1000 / 1000).
|
||||
@ref CONFIG_COAP_ACK_TIMEOUT_MS and
|
||||
(@ref CONFIG_COAP_ACK_TIMEOUT_MS * @ref CONFIG_COAP_RANDOM_FACTOR_1000 / 1000).
|
||||
The default of 2 seconds is taken from
|
||||
[RFC 7252, section 4.8](https://tools.ietf.org/html/rfc7252#section-4.8).
|
||||
|
||||
|
@ -47,7 +47,7 @@
|
||||
#define NO_IMMEDIATE_REPLY (-1)
|
||||
|
||||
/* End of the range to pick a random timeout */
|
||||
#define TIMEOUT_RANGE_END (CONFIG_COAP_ACK_TIMEOUT * CONFIG_COAP_RANDOM_FACTOR_1000 / 1000)
|
||||
#define TIMEOUT_RANGE_END (CONFIG_COAP_ACK_TIMEOUT_MS * CONFIG_COAP_RANDOM_FACTOR_1000 / 1000)
|
||||
|
||||
/* Internal functions */
|
||||
static void *_event_loop(void *arg);
|
||||
@ -66,7 +66,7 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
static void _expire_request(gcoap_request_memo_t *memo);
|
||||
static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu,
|
||||
const sock_udp_ep_t *remote, bool by_mid);
|
||||
static int _find_resource(const coap_pkt_t *pdu,
|
||||
static int _find_resource(coap_pkt_t *pdu,
|
||||
const coap_resource_t **resource_ptr,
|
||||
gcoap_listener_t **listener_ptr);
|
||||
static int _find_observer(sock_udp_ep_t **observer, sock_udp_ep_t *remote);
|
||||
@ -77,7 +77,7 @@ static void _find_obs_memo_resource(gcoap_observe_memo_t **memo,
|
||||
|
||||
static int _request_matcher_default(gcoap_listener_t *listener,
|
||||
const coap_resource_t **resource,
|
||||
const coap_pkt_t *pdu);
|
||||
coap_pkt_t *pdu);
|
||||
|
||||
#if IS_USED(MODULE_GCOAP_DTLS)
|
||||
static void _on_sock_dtls_evt(sock_dtls_t *sock, sock_async_flags_t type, void *arg);
|
||||
@ -472,9 +472,9 @@ static void _on_resp_timeout(void *arg) {
|
||||
#else
|
||||
unsigned i = CONFIG_COAP_MAX_RETRANSMIT - memo->send_limit;
|
||||
#endif
|
||||
uint32_t timeout = ((uint32_t)CONFIG_COAP_ACK_TIMEOUT << i) * MS_PER_SEC;
|
||||
uint32_t timeout = (uint32_t)CONFIG_COAP_ACK_TIMEOUT_MS << i;
|
||||
#if CONFIG_COAP_RANDOM_FACTOR_1000 > 1000
|
||||
uint32_t end = ((uint32_t)TIMEOUT_RANGE_END << i) * MS_PER_SEC;
|
||||
uint32_t end = (uint32_t)TIMEOUT_RANGE_END << i;
|
||||
timeout = random_uint32_range(timeout, end);
|
||||
#endif
|
||||
event_timeout_set(&memo->resp_evt_tmout, timeout);
|
||||
@ -538,7 +538,7 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
gcoap_observe_memo_t *memo = NULL;
|
||||
gcoap_observe_memo_t *resource_memo = NULL;
|
||||
|
||||
switch (_find_resource((const coap_pkt_t *)pdu, &resource, &listener)) {
|
||||
switch (_find_resource(pdu, &resource, &listener)) {
|
||||
case GCOAP_RESOURCE_WRONG_METHOD:
|
||||
return gcoap_response(pdu, buf, len, COAP_CODE_METHOD_NOT_ALLOWED);
|
||||
case GCOAP_RESOURCE_NO_PATH:
|
||||
@ -640,7 +640,7 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
|
||||
static int _request_matcher_default(gcoap_listener_t *listener,
|
||||
const coap_resource_t **resource,
|
||||
const coap_pkt_t *pdu)
|
||||
coap_pkt_t *pdu)
|
||||
{
|
||||
uint8_t uri[CONFIG_NANOCOAP_URI_MAX];
|
||||
int ret = GCOAP_RESOURCE_NO_PATH;
|
||||
@ -696,7 +696,7 @@ static int _request_matcher_default(gcoap_listener_t *listener,
|
||||
* code didn't match and `GCOAP_RESOURCE_NO_PATH` if no matching
|
||||
* resource was found.
|
||||
*/
|
||||
static int _find_resource(const coap_pkt_t *pdu,
|
||||
static int _find_resource(coap_pkt_t *pdu,
|
||||
const coap_resource_t **resource_ptr,
|
||||
gcoap_listener_t **listener_ptr)
|
||||
{
|
||||
@ -1158,9 +1158,9 @@ ssize_t gcoap_req_send(const uint8_t *buf, size_t len,
|
||||
}
|
||||
if (memo->msg.data.pdu_buf) {
|
||||
memo->send_limit = CONFIG_COAP_MAX_RETRANSMIT;
|
||||
timeout = (uint32_t)CONFIG_COAP_ACK_TIMEOUT * MS_PER_SEC;
|
||||
timeout = (uint32_t)CONFIG_COAP_ACK_TIMEOUT_MS;
|
||||
#if CONFIG_COAP_RANDOM_FACTOR_1000 > 1000
|
||||
timeout = random_uint32_range(timeout, TIMEOUT_RANGE_END * MS_PER_SEC);
|
||||
timeout = random_uint32_range(timeout, TIMEOUT_RANGE_END);
|
||||
#endif
|
||||
memo->state = GCOAP_MEMO_RETRANSMIT;
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ int coap_parse(coap_pkt_t *pkt, uint8_t *buf, size_t len)
|
||||
|
||||
pkt->payload = NULL;
|
||||
pkt->payload_len = 0;
|
||||
memset(pkt->opt_crit, 0, sizeof(pkt->opt_crit));
|
||||
|
||||
if (len < sizeof(coap_hdr_t)) {
|
||||
DEBUG("msg too short\n");
|
||||
@ -126,6 +127,10 @@ int coap_parse(coap_pkt_t *pkt, uint8_t *buf, size_t len)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* check if option is critical */
|
||||
if (option_nr & 1) {
|
||||
bf_set(pkt->opt_crit, option_count);
|
||||
}
|
||||
optpos->opt_num = option_nr;
|
||||
optpos->offset = (uintptr_t)option_start - (uintptr_t)hdr;
|
||||
DEBUG("optpos option_nr=%u %u\n", (unsigned)option_nr, (unsigned)optpos->offset);
|
||||
@ -176,13 +181,15 @@ int coap_match_path(const coap_resource_t *resource, uint8_t *uri)
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t *coap_find_option(const coap_pkt_t *pkt, unsigned opt_num)
|
||||
uint8_t *coap_find_option(coap_pkt_t *pkt, unsigned opt_num)
|
||||
{
|
||||
const coap_optpos_t *optpos = pkt->options;
|
||||
unsigned opt_count = pkt->options_len;
|
||||
|
||||
while (opt_count--) {
|
||||
if (optpos->opt_num == opt_num) {
|
||||
unsigned idx = index_of(pkt->options, optpos);
|
||||
bf_unset(pkt->opt_crit, idx);
|
||||
return (uint8_t*)pkt->hdr + optpos->offset;
|
||||
}
|
||||
optpos++;
|
||||
@ -219,7 +226,7 @@ static uint8_t *_parse_option(const coap_pkt_t *pkt,
|
||||
return pkt_pos;
|
||||
}
|
||||
|
||||
ssize_t coap_opt_get_opaque(const coap_pkt_t *pkt, unsigned opt_num, uint8_t **value)
|
||||
ssize_t coap_opt_get_opaque(coap_pkt_t *pkt, unsigned opt_num, uint8_t **value)
|
||||
{
|
||||
uint8_t *start = coap_find_option(pkt, opt_num);
|
||||
if (!start) {
|
||||
@ -237,7 +244,7 @@ ssize_t coap_opt_get_opaque(const coap_pkt_t *pkt, unsigned opt_num, uint8_t **v
|
||||
return len;
|
||||
}
|
||||
|
||||
int coap_opt_get_uint(const coap_pkt_t *pkt, uint16_t opt_num, uint32_t *target)
|
||||
int coap_opt_get_uint(coap_pkt_t *pkt, uint16_t opt_num, uint32_t *target)
|
||||
{
|
||||
assert(target);
|
||||
|
||||
@ -262,7 +269,7 @@ int coap_opt_get_uint(const coap_pkt_t *pkt, uint16_t opt_num, uint32_t *target)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
uint8_t *coap_iterate_option(const coap_pkt_t *pkt, uint8_t **optpos,
|
||||
uint8_t *coap_iterate_option(coap_pkt_t *pkt, uint8_t **optpos,
|
||||
int *opt_len, int first)
|
||||
{
|
||||
uint8_t *data_start;
|
||||
@ -325,7 +332,7 @@ ssize_t coap_opt_get_next(const coap_pkt_t *pkt, coap_optpos_t *opt,
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t coap_opt_get_string(const coap_pkt_t *pkt, uint16_t optnum,
|
||||
ssize_t coap_opt_get_string(coap_pkt_t *pkt, uint16_t optnum,
|
||||
uint8_t *target, size_t max_len, char separator)
|
||||
{
|
||||
assert(pkt && target && (max_len > 1));
|
||||
@ -392,6 +399,17 @@ int coap_get_blockopt(coap_pkt_t *pkt, uint16_t option, uint32_t *blknum, unsign
|
||||
return (blkopt & 0x8) ? 1 : 0;
|
||||
}
|
||||
|
||||
bool coap_has_unprocessed_critical_options(const coap_pkt_t *pkt)
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(pkt->opt_crit); ++i){
|
||||
if (pkt->opt_crit[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t coap_handle_req(coap_pkt_t *pkt, uint8_t *resp_buf, unsigned resp_buf_len)
|
||||
{
|
||||
if (coap_get_code_class(pkt) != COAP_REQ) {
|
||||
|
@ -25,51 +25,69 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "net/nanocoap_sock.h"
|
||||
#include "net/sock/util.h"
|
||||
#include "net/sock/udp.h"
|
||||
#include "timex.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
ssize_t nanocoap_request(coap_pkt_t *pkt, sock_udp_ep_t *local, sock_udp_ep_t *remote, size_t len)
|
||||
int nanocoap_sock_connect(nanocoap_sock_t *sock, sock_udp_ep_t *local, sock_udp_ep_t *remote)
|
||||
{
|
||||
ssize_t res;
|
||||
size_t pdu_len = (pkt->payload - (uint8_t *)pkt->hdr) + pkt->payload_len;
|
||||
uint8_t *buf = (uint8_t*)pkt->hdr;
|
||||
sock_udp_t sock;
|
||||
|
||||
if (!remote->port) {
|
||||
remote->port = COAP_PORT;
|
||||
}
|
||||
|
||||
res = sock_udp_create(&sock, local, remote, 0);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
return sock_udp_create(sock, local, remote, 0);
|
||||
}
|
||||
|
||||
ssize_t nanocoap_sock_request(nanocoap_sock_t *sock, coap_pkt_t *pkt, size_t len)
|
||||
{
|
||||
ssize_t res = -EAGAIN;
|
||||
size_t pdu_len = (pkt->payload - (uint8_t *)pkt->hdr) + pkt->payload_len;
|
||||
uint8_t *buf = (uint8_t*)pkt->hdr;
|
||||
uint32_t id = coap_get_id(pkt);
|
||||
|
||||
/* TODO: timeout random between between ACK_TIMEOUT and (ACK_TIMEOUT *
|
||||
* ACK_RANDOM_FACTOR) */
|
||||
uint32_t timeout = CONFIG_COAP_ACK_TIMEOUT * US_PER_SEC;
|
||||
unsigned tries_left = CONFIG_COAP_MAX_RETRANSMIT + 1; /* add 1 for initial transmit */
|
||||
while (tries_left) {
|
||||
uint32_t timeout = CONFIG_COAP_ACK_TIMEOUT_MS * US_PER_MS;
|
||||
|
||||
res = sock_udp_send(&sock, buf, pdu_len, NULL);
|
||||
if (res <= 0) {
|
||||
DEBUG("nanocoap: error sending coap request, %d\n", (int)res);
|
||||
/* add 1 for initial transmit */
|
||||
unsigned tries_left = CONFIG_COAP_MAX_RETRANSMIT + 1;
|
||||
|
||||
/* check if we expect a reply */
|
||||
bool confirmable = coap_get_type(pkt) == COAP_TYPE_CON;
|
||||
|
||||
while (tries_left) {
|
||||
if (res == -EAGAIN) {
|
||||
res = sock_udp_send(sock, buf, pdu_len, NULL);
|
||||
if (res <= 0) {
|
||||
DEBUG("nanocoap: error sending coap request, %d\n", (int)res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* return if no response is expected */
|
||||
if (!confirmable) {
|
||||
pkt->payload_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
res = sock_udp_recv(&sock, buf, len, timeout, NULL);
|
||||
res = sock_udp_recv(sock, buf, len, timeout, NULL);
|
||||
if (res <= 0) {
|
||||
if (res == -ETIMEDOUT) {
|
||||
DEBUG("nanocoap: timeout\n");
|
||||
|
||||
timeout *= 2;
|
||||
tries_left--;
|
||||
if (!tries_left) {
|
||||
DEBUG("nanocoap: maximum retries reached\n");
|
||||
break;
|
||||
}
|
||||
else {
|
||||
timeout *= 2;
|
||||
res = -EAGAIN;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
DEBUG("nanocoap: error receiving coap response, %d\n", (int)res);
|
||||
break;
|
||||
@ -79,28 +97,31 @@ ssize_t nanocoap_request(coap_pkt_t *pkt, sock_udp_ep_t *local, sock_udp_ep_t *r
|
||||
DEBUG("nanocoap: error parsing packet\n");
|
||||
res = -EBADMSG;
|
||||
}
|
||||
else if (coap_get_id(pkt) != id) {
|
||||
res = -EBADMSG;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sock_udp_close(&sock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, uint8_t *buf, size_t len)
|
||||
ssize_t nanocoap_sock_get(nanocoap_sock_t *sock, const char *path, void *buf, size_t len)
|
||||
{
|
||||
ssize_t res;
|
||||
coap_pkt_t pkt;
|
||||
uint8_t *pktpos = buf;
|
||||
|
||||
pkt.hdr = (coap_hdr_t*)buf;
|
||||
pkt.hdr = buf;
|
||||
pktpos += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_GET, 1);
|
||||
pktpos += coap_opt_put_uri_path(pktpos, 0, path);
|
||||
pkt.payload = pktpos;
|
||||
pkt.payload_len = 0;
|
||||
|
||||
res = nanocoap_request(&pkt, NULL, remote, len);
|
||||
res = nanocoap_sock_request(sock, &pkt, len);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
@ -119,9 +140,148 @@ ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, uint8_t *buf, size
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t nanocoap_request(coap_pkt_t *pkt, sock_udp_ep_t *local,
|
||||
sock_udp_ep_t *remote, size_t len)
|
||||
{
|
||||
int res;
|
||||
nanocoap_sock_t sock;
|
||||
|
||||
res = nanocoap_sock_connect(&sock, local, remote);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = nanocoap_sock_request(&sock, pkt, len);
|
||||
nanocoap_sock_close(&sock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, void *buf, size_t len)
|
||||
{
|
||||
int res;
|
||||
nanocoap_sock_t sock;
|
||||
|
||||
res = nanocoap_sock_connect(&sock, NULL, remote);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = nanocoap_sock_get(&sock, path, buf, len);
|
||||
nanocoap_sock_close(&sock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _fetch_block(coap_pkt_t *pkt, uint8_t *buf, nanocoap_sock_t *sock,
|
||||
const char *path, coap_blksize_t blksize, size_t num)
|
||||
{
|
||||
uint8_t *pktpos = buf;
|
||||
uint16_t lastonum = 0;
|
||||
|
||||
pkt->hdr = (coap_hdr_t *)buf;
|
||||
|
||||
pktpos += coap_build_hdr(pkt->hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_GET,
|
||||
num);
|
||||
pktpos += coap_opt_put_uri_pathquery(pktpos, &lastonum, path);
|
||||
pktpos += coap_opt_put_uint(pktpos, lastonum, COAP_OPT_BLOCK2,
|
||||
(num << 4) | blksize);
|
||||
|
||||
pkt->payload = pktpos;
|
||||
pkt->payload_len = 0;
|
||||
|
||||
int res = nanocoap_sock_request(sock, pkt, NANOCOAP_BLOCKWISE_BUF(blksize));
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = coap_get_code(pkt);
|
||||
DEBUG("code=%i\n", res);
|
||||
if (res != 205) {
|
||||
return -res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nanocoap_sock_get_blockwise(nanocoap_sock_t *sock, const char *path,
|
||||
coap_blksize_t blksize, void *buf,
|
||||
coap_blockwise_cb_t callback, void *arg)
|
||||
{
|
||||
coap_pkt_t pkt;
|
||||
coap_block1_t block2;
|
||||
|
||||
size_t num = 0;
|
||||
do {
|
||||
DEBUG("fetching block %u\n", (unsigned)num);
|
||||
int res = _fetch_block(&pkt, buf, sock, path, blksize, num);
|
||||
if (res) {
|
||||
DEBUG("error fetching block: %d\n", res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* no block option in response - directly use paylaod */
|
||||
if (!coap_get_block2(&pkt, &block2)) {
|
||||
block2.more = 0;
|
||||
block2.offset = 0;
|
||||
}
|
||||
|
||||
if (coap_has_unprocessed_critical_options(&pkt)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
res = callback(arg, block2.offset, pkt.payload, pkt.payload_len,
|
||||
block2.more);
|
||||
if (res) {
|
||||
DEBUG("callback %d != 0, aborting.\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
num += 1;
|
||||
} while (block2.more == 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nanocoap_get_blockwise_url(const char *url,
|
||||
coap_blksize_t blksize, void *buf,
|
||||
coap_blockwise_cb_t callback, void *arg)
|
||||
{
|
||||
char hostport[CONFIG_SOCK_HOSTPORT_MAXLEN];
|
||||
char urlpath[CONFIG_SOCK_URLPATH_MAXLEN];
|
||||
sock_udp_ep_t remote;
|
||||
nanocoap_sock_t sock;
|
||||
int res;
|
||||
|
||||
if (strncmp(url, "coap://", 7)) {
|
||||
DEBUG("nanocoap: URL doesn't start with \"coap://\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sock_urlsplit(url, hostport, urlpath) < 0) {
|
||||
DEBUG("nanocoap: invalid URL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sock_udp_str2ep(&remote, hostport) < 0) {
|
||||
DEBUG("nanocoap: invalid URL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = nanocoap_sock_connect(&sock, NULL, &remote);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = nanocoap_sock_get_blockwise(&sock, urlpath, blksize, buf, callback, arg);
|
||||
nanocoap_sock_close(&sock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int nanocoap_server(sock_udp_ep_t *local, uint8_t *buf, size_t bufsize)
|
||||
{
|
||||
sock_udp_t sock;
|
||||
nanocoap_sock_t sock;
|
||||
sock_udp_ep_t remote;
|
||||
|
||||
if (!local->port) {
|
||||
|
@ -37,6 +37,7 @@
|
||||
|
||||
#ifdef MODULE_SUIT_TRANSPORT_COAP
|
||||
#include "suit/transport/coap.h"
|
||||
#include "net/nanocoap_sock.h"
|
||||
#endif
|
||||
#include "suit/transport/mock.h"
|
||||
|
||||
@ -358,9 +359,10 @@ static int _dtv_fetch(suit_manifest_t *manifest, int key,
|
||||
if (0) {}
|
||||
#ifdef MODULE_SUIT_TRANSPORT_COAP
|
||||
else if (strncmp(manifest->urlbuf, "coap://", 7) == 0) {
|
||||
res = suit_coap_get_blockwise_url(manifest->urlbuf, CONFIG_SUIT_COAP_BLOCKSIZE,
|
||||
suit_storage_helper,
|
||||
manifest);
|
||||
uint8_t buffer[NANOCOAP_BLOCKWISE_BUF(CONFIG_SUIT_COAP_BLOCKSIZE)];
|
||||
res = nanocoap_get_blockwise_url(manifest->urlbuf, CONFIG_SUIT_COAP_BLOCKSIZE,
|
||||
buffer, suit_storage_helper,
|
||||
manifest);
|
||||
}
|
||||
#endif
|
||||
#ifdef MODULE_SUIT_TRANSPORT_MOCK
|
||||
|
@ -133,181 +133,6 @@ static inline uint32_t deadline_left(uint32_t deadline)
|
||||
return left;
|
||||
}
|
||||
|
||||
static ssize_t _nanocoap_request(sock_udp_t *sock, coap_pkt_t *pkt, size_t len)
|
||||
{
|
||||
ssize_t res = -EAGAIN;
|
||||
size_t pdu_len = (pkt->payload - (uint8_t *)pkt->hdr) + pkt->payload_len;
|
||||
uint8_t *buf = (uint8_t *)pkt->hdr;
|
||||
uint32_t id = coap_get_id(pkt);
|
||||
|
||||
/* TODO: timeout random between between ACK_TIMEOUT and (ACK_TIMEOUT *
|
||||
* ACK_RANDOM_FACTOR) */
|
||||
uint32_t timeout = CONFIG_COAP_ACK_TIMEOUT * US_PER_SEC;
|
||||
uint32_t deadline = deadline_from_interval(timeout);
|
||||
|
||||
/* add 1 for initial transmit */
|
||||
unsigned tries_left = CONFIG_COAP_MAX_RETRANSMIT + 1;
|
||||
|
||||
while (tries_left) {
|
||||
if (res == -EAGAIN) {
|
||||
res = sock_udp_send(sock, buf, pdu_len, NULL);
|
||||
if (res <= 0) {
|
||||
DEBUG("nanocoap: error sending coap request, %d\n", (int)res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res = sock_udp_recv(sock, buf, len, deadline_left(deadline), NULL);
|
||||
if (res <= 0) {
|
||||
if (res == -ETIMEDOUT) {
|
||||
DEBUG("nanocoap: timeout\n");
|
||||
|
||||
tries_left--;
|
||||
if (!tries_left) {
|
||||
DEBUG("nanocoap: maximum retries reached\n");
|
||||
break;
|
||||
}
|
||||
else {
|
||||
timeout *= 2;
|
||||
deadline = deadline_from_interval(timeout);
|
||||
res = -EAGAIN;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
DEBUG("nanocoap: error receiving coap response, %d\n", (int)res);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (coap_parse(pkt, (uint8_t *)buf, res) < 0) {
|
||||
DEBUG("nanocoap: error parsing packet\n");
|
||||
res = -EBADMSG;
|
||||
}
|
||||
else if (coap_get_id(pkt) != id) {
|
||||
res = -EBADMSG;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _fetch_block(coap_pkt_t *pkt, uint8_t *buf, sock_udp_t *sock,
|
||||
const char *path, coap_blksize_t blksize, size_t num)
|
||||
{
|
||||
uint8_t *pktpos = buf;
|
||||
uint16_t lastonum = 0;
|
||||
|
||||
pkt->hdr = (coap_hdr_t *)buf;
|
||||
|
||||
pktpos += coap_build_hdr(pkt->hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_GET,
|
||||
num);
|
||||
pktpos += coap_opt_put_uri_pathquery(pktpos, &lastonum, path);
|
||||
pktpos +=
|
||||
coap_opt_put_uint(pktpos, lastonum, COAP_OPT_BLOCK2,
|
||||
(num << 4) | blksize);
|
||||
|
||||
pkt->payload = pktpos;
|
||||
pkt->payload_len = 0;
|
||||
|
||||
int res = _nanocoap_request(sock, pkt, 64 + (0x1 << (blksize + 4)));
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = coap_get_code(pkt);
|
||||
DEBUG("code=%i\n", res);
|
||||
if (res != 205) {
|
||||
return -res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int suit_coap_get_blockwise(sock_udp_ep_t *remote, const char *path,
|
||||
coap_blksize_t blksize,
|
||||
coap_blockwise_cb_t callback, void *arg)
|
||||
{
|
||||
/* mmmmh dynamically sized array */
|
||||
uint8_t buf[64 + (0x1 << (blksize + 4))];
|
||||
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
|
||||
coap_pkt_t pkt;
|
||||
|
||||
/* HACK: use random local port */
|
||||
local.port = 0x8000 + (xtimer_now_usec() % 0XFFF);
|
||||
|
||||
sock_udp_t sock;
|
||||
int res = sock_udp_create(&sock, &local, remote, 0);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
int more = 1;
|
||||
size_t num = 0;
|
||||
res = -1;
|
||||
while (more == 1) {
|
||||
DEBUG("fetching block %u\n", (unsigned)num);
|
||||
res = _fetch_block(&pkt, buf, &sock, path, blksize, num);
|
||||
DEBUG("res=%i\n", res);
|
||||
|
||||
if (!res) {
|
||||
coap_block1_t block2;
|
||||
coap_get_block2(&pkt, &block2);
|
||||
more = block2.more;
|
||||
|
||||
if (callback(arg, block2.offset, pkt.payload, pkt.payload_len,
|
||||
more)) {
|
||||
DEBUG("callback res != 0, aborting.\n");
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG("error fetching block\n");
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
num += 1;
|
||||
}
|
||||
|
||||
out:
|
||||
sock_udp_close(&sock);
|
||||
return res;
|
||||
}
|
||||
|
||||
int suit_coap_get_blockwise_url(const char *url,
|
||||
coap_blksize_t blksize,
|
||||
coap_blockwise_cb_t callback, void *arg)
|
||||
{
|
||||
char hostport[CONFIG_SOCK_HOSTPORT_MAXLEN];
|
||||
char urlpath[CONFIG_SOCK_URLPATH_MAXLEN];
|
||||
sock_udp_ep_t remote;
|
||||
|
||||
if (strncmp(url, "coap://", 7)) {
|
||||
LOG_INFO("suit: URL doesn't start with \"coap://\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sock_urlsplit(url, hostport, urlpath) < 0) {
|
||||
LOG_INFO("suit: invalid URL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sock_udp_str2ep(&remote, hostport) < 0) {
|
||||
LOG_INFO("suit: invalid URL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!remote.port) {
|
||||
remote.port = COAP_PORT;
|
||||
}
|
||||
|
||||
return suit_coap_get_blockwise(&remote, urlpath, blksize, callback, arg);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
size_t offset;
|
||||
uint8_t *ptr;
|
||||
@ -334,20 +159,20 @@ static int _2buf(void *arg, size_t offset, uint8_t *buf, size_t len, int more)
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t suit_coap_get_blockwise_url_buf(const char *url,
|
||||
coap_blksize_t blksize,
|
||||
uint8_t *buf, size_t len)
|
||||
static ssize_t suit_coap_get_blockwise_url_buf(const char *url,
|
||||
coap_blksize_t blksize, void *work_buf,
|
||||
uint8_t *buf, size_t len)
|
||||
{
|
||||
_buf_t _buf = { .ptr = buf, .len = len };
|
||||
int res = suit_coap_get_blockwise_url(url, blksize, _2buf, &_buf);
|
||||
int res = nanocoap_get_blockwise_url(url, blksize, work_buf, _2buf, &_buf);
|
||||
|
||||
return (res < 0) ? (ssize_t)res : (ssize_t)_buf.offset;
|
||||
}
|
||||
|
||||
static void _suit_handle_url(const char *url)
|
||||
static void _suit_handle_url(const char *url, coap_blksize_t blksize, void *work_buf)
|
||||
{
|
||||
LOG_INFO("suit_coap: downloading \"%s\"\n", url);
|
||||
ssize_t size = suit_coap_get_blockwise_url_buf(url, CONFIG_SUIT_COAP_BLOCKSIZE,
|
||||
ssize_t size = suit_coap_get_blockwise_url_buf(url, blksize, work_buf,
|
||||
_manifest_buf,
|
||||
SUIT_MANIFEST_BUFSIZE);
|
||||
if (size >= 0) {
|
||||
@ -436,6 +261,8 @@ static void *_suit_coap_thread(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
uint8_t buffer[NANOCOAP_BLOCKWISE_BUF(CONFIG_SUIT_COAP_BLOCKSIZE)];
|
||||
|
||||
LOG_INFO("suit_coap: started.\n");
|
||||
msg_t msg_queue[4];
|
||||
msg_init_queue(msg_queue, 4);
|
||||
@ -449,7 +276,7 @@ static void *_suit_coap_thread(void *arg)
|
||||
switch (m.content.value) {
|
||||
case SUIT_MSG_TRIGGER:
|
||||
LOG_INFO("suit_coap: trigger received\n");
|
||||
_suit_handle_url(_url);
|
||||
_suit_handle_url(_url, CONFIG_SUIT_COAP_BLOCKSIZE, buffer);
|
||||
break;
|
||||
default:
|
||||
LOG_WARNING("suit_coap: warning: unhandled msg\n");
|
||||
|
@ -29,11 +29,13 @@
|
||||
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
|
||||
|
||||
extern int nanotest_client_cmd(int argc, char **argv);
|
||||
extern int nanotest_client_url_cmd(int argc, char **argv);
|
||||
extern int nanotest_server_cmd(int argc, char **argv);
|
||||
static int _list_all_inet6(int argc, char **argv);
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "client", "CoAP client", nanotest_client_cmd },
|
||||
{ "url", "CoAP client URL request", nanotest_client_url_cmd },
|
||||
{ "server", "CoAP server", nanotest_server_cmd },
|
||||
{ "inet6", "IPv6 addresses", _list_all_inet6 },
|
||||
{ NULL, NULL, NULL }
|
||||
|
@ -80,7 +80,7 @@ static ssize_t _send(coap_pkt_t *pkt, size_t len, char *addr_str, char *port_str
|
||||
int nanotest_client_cmd(int argc, char **argv)
|
||||
{
|
||||
/* Ordered like the RFC method code numbers, but off by 1. GET is code 0. */
|
||||
char *method_codes[] = {"get", "post", "put"};
|
||||
const char *method_codes[] = {"get", "post", "put"};
|
||||
unsigned buflen = 128;
|
||||
uint8_t buf[buflen];
|
||||
coap_pkt_t pkt;
|
||||
@ -161,3 +161,50 @@ int nanotest_client_cmd(int argc, char **argv)
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _blockwise_cb(void *arg, size_t offset, uint8_t *buf, size_t len, int more)
|
||||
{
|
||||
(void)arg;
|
||||
(void)more;
|
||||
|
||||
printf("offset %03u: ", (unsigned)offset);
|
||||
for (unsigned i = 0; i < len; ++i) {
|
||||
putchar(buf[i]);
|
||||
}
|
||||
puts("");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nanotest_client_url_cmd(int argc, char **argv)
|
||||
{
|
||||
/* Ordered like the RFC method code numbers, but off by 1. GET is code 0. */
|
||||
const char *method_codes[] = {"get", "post", "put"};
|
||||
|
||||
if (argc < 3) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
int code_pos = -1;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(method_codes); i++) {
|
||||
if (strcmp(argv[1], method_codes[i]) == 0) {
|
||||
code_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (code_pos == -1) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (code_pos != 0) {
|
||||
printf("TODO: implement %s request\n", method_codes[code_pos]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t buffer[NANOCOAP_BLOCKWISE_BUF(COAP_BLOCKSIZE_32)];
|
||||
return nanocoap_get_blockwise_url(argv[2], COAP_BLOCKSIZE_32, buffer,
|
||||
_blockwise_cb, NULL);
|
||||
error:
|
||||
printf("usage: %s <get|post|put> <url> [data]\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user