Merge pull request #7096 from haukepetersen/opt_gcoap_misc2

net/gcoap: some more minor improvements
This commit is contained in:
Hauke Petersen 2017-06-01 12:54:11 +02:00 committed by GitHub
commit 4bc1d2916b
2 changed files with 160 additions and 128 deletions

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2015-2016 Ken Bannister. All rights reserved.
* 2017 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -174,12 +175,17 @@
* ## Implementation Status ##
* gcoap includes server and client capability. Available features include:
*
* - Message Type: Supports non-confirmable (NON) messaging. Additionally provides a callback on timeout.
* - Message Type: Supports non-confirmable (NON) messaging. Additionally
* provides a callback on timeout.
* - Observe extension: Provides server-side registration and notifications.
* - Server and Client provide helper functions for writing the response/request. See the CoAP topic in the source documentation for details. See the gcoap example for sample implementations.
* - Server allows an application to register a 'listener', which includes an array of endpoint paths and function callbacks used to write a response.
* - Server and Client provide helper functions for writing the
* response/request. See the CoAP topic in the source documentation for
* details. See the gcoap example for sample implementations.
* - Server allows an application to register a 'listener', which includes an
* array of endpoint paths and function callbacks used to write a response.
* - Server listens on a port at startup; defaults to 5683.
* - Client operates asynchronously; sends request and then handles response in a user provided callback.
* - Client operates asynchronously; sends request and then handles response
* in a user provided callback.
* - Client generates token; length defined at compile time.
* - Options: Supports Content-Format for payload.
*
@ -189,6 +195,7 @@
* @brief gcoap definition
*
* @author Ken Bannister <kb2ma@runbox.com>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef NET_GCOAP_H
@ -202,113 +209,134 @@
extern "C" {
#endif
/** @brief Size for module message queue */
/**
* @brief Size for module message queue
*/
#define GCOAP_MSG_QUEUE_SIZE (4)
/** @brief Server port; use RFC 7252 default if not defined */
/**
* @brief Server port; use RFC 7252 default if not defined
*/
#ifndef GCOAP_PORT
#define GCOAP_PORT (5683)
#endif
/** @brief Size of the buffer used to build a CoAP request or response. */
/**
* @brief Size of the buffer used to build a CoAP request or response
*/
#define GCOAP_PDU_BUF_SIZE (128)
/**
* @brief Size of the buffer used to write options, other than Uri-Path, in a
* request.
* @brief Size of the buffer used to write options, other than Uri-Path, in a
* request
*
* Accommodates Content-Format.
*/
#define GCOAP_REQ_OPTIONS_BUF (8)
/**
* @brief Size of the buffer used to write options in a response.
* @brief Size of the buffer used to write options in a response
*
* Accommodates Content-Format.
*/
#define GCOAP_RESP_OPTIONS_BUF (8)
/**
* @brief Size of the buffer used to write options in an Observe notification.
* @brief Size of the buffer used to write options in an Observe notification
*
* Accommodates Content-Format and Observe.
*/
#define GCOAP_OBS_OPTIONS_BUF (8)
#define GCOAP_OBS_OPTIONS_BUF (8)
/** @brief Maximum number of requests awaiting a response */
/**
* @brief Maximum number of requests awaiting a response
*/
#define GCOAP_REQ_WAITING_MAX (2)
/** @brief Maximum length in bytes for a token */
/**
* @brief Maximum length in bytes for a token
*/
#define GCOAP_TOKENLEN_MAX (8)
/** @brief Maximum length in bytes for a header, including the token */
/**
* @brief Maximum length in bytes for a header, including the token
*/
#define GCOAP_HEADER_MAXLEN (sizeof(coap_hdr_t) + GCOAP_TOKENLEN_MAX)
/** @brief Length in bytes for a token; use 2 if not defined */
/**
* @brief Length in bytes for a token; use 2 if not defined
*/
#ifndef GCOAP_TOKENLEN
#define GCOAP_TOKENLEN (2)
#endif
/** @brief Marks the boundary between header and payload */
/**
* @brief Marks the boundary between header and payload
*/
#define GCOAP_PAYLOAD_MARKER (0xFF)
/**
* @name States for the memo used to track waiting for a response
* @name States for the memo used to track waiting for a response
* @{
*/
#define GCOAP_MEMO_UNUSED (0) /**< This memo is unused */
#define GCOAP_MEMO_WAIT (1) /**< Request sent; awaiting response */
#define GCOAP_MEMO_RESP (2) /**< Got response */
#define GCOAP_MEMO_TIMEOUT (3) /**< Timeout waiting for response */
#define GCOAP_MEMO_ERR (4) /**< Error processing response packet */
#define GCOAP_MEMO_UNUSED (0) /**< This memo is unused */
#define GCOAP_MEMO_WAIT (1) /**< Request sent; awaiting response */
#define GCOAP_MEMO_RESP (2) /**< Got response */
#define GCOAP_MEMO_TIMEOUT (3) /**< Timeout waiting for response */
#define GCOAP_MEMO_ERR (4) /**< Error processing response packet */
/** @} */
/** @brief Time in usec that the event loop waits for an incoming CoAP message */
/**
* @brief Time in usec that the event loop waits for an incoming CoAP message
*/
#define GCOAP_RECV_TIMEOUT (1 * US_PER_SEC)
/**
*
* @brief Default time to wait for a non-confirmable response, in usec
* @brief Default time to wait for a non-confirmable response [in usec]
*
* Set to 0 to disable timeout.
*/
#define GCOAP_NON_TIMEOUT (5000000U)
/** @brief Identifies waiting timed out for a response to a sent message. */
/**
* @brief Identifies waiting timed out for a response to a sent message
*/
#define GCOAP_MSG_TYPE_TIMEOUT (0x1501)
/**
* @brief Identifies a request to interrupt listening for an incoming message
* on a sock.
* @brief Identifies a request to interrupt listening for an incoming message
* on a sock
*
* Allows the event loop to process IPC messages.
*/
#define GCOAP_MSG_TYPE_INTR (0x1502)
/** @brief Maximum number of Observe clients; use 2 if not defined */
/**
* @brief Maximum number of Observe clients; use 2 if not defined
*/
#ifndef GCOAP_OBS_CLIENTS_MAX
#define GCOAP_OBS_CLIENTS_MAX (2)
#define GCOAP_OBS_CLIENTS_MAX (2)
#endif
/**
* @brief Maximum number of registrations for Observable resources; use 2 if
* not defined
* @brief Maximum number of registrations for Observable resources; use 2 if
* not defined
*/
#ifndef GCOAP_OBS_REGISTRATIONS_MAX
#define GCOAP_OBS_REGISTRATIONS_MAX (2)
#define GCOAP_OBS_REGISTRATIONS_MAX (2)
#endif
/**
* @name States for the memo used to track Observe registrations
* @name States for the memo used to track Observe registrations
* @{
*/
#define GCOAP_OBS_MEMO_UNUSED (0) /**< This memo is unused */
#define GCOAP_OBS_MEMO_IDLE (1) /**< Registration OK; no current activity */
#define GCOAP_OBS_MEMO_PENDING (2) /**< Resource changed; notification pending */
#define GCOAP_OBS_MEMO_UNUSED (0) /**< This memo is unused */
#define GCOAP_OBS_MEMO_IDLE (1) /**< Registration OK; no current activity */
#define GCOAP_OBS_MEMO_PENDING (2) /**< Resource changed; notification pending */
/** @} */
/**
* @brief Width in bytes of the Observe option value for a notification.
* @brief Width in bytes of the Observe option value for a notification
*
* This width is used to determine the length of the 'tick' used to measure
* the time between observable changes to a resource. A tick is expressed
@ -327,10 +355,12 @@ extern "C" {
* useful when packet size is limited.
*/
#ifndef GCOAP_OBS_VALUE_WIDTH
#define GCOAP_OBS_VALUE_WIDTH (3)
#define GCOAP_OBS_VALUE_WIDTH (3)
#endif
/** @brief See GCOAP_OBS_VALUE_WIDTH. */
/**
* @brief See GCOAP_OBS_VALUE_WIDTH
*/
#if (GCOAP_OBS_VALUE_WIDTH == 3)
#define GCOAP_OBS_TICK_EXPONENT (5)
#elif (GCOAP_OBS_VALUE_WIDTH == 2)
@ -340,16 +370,16 @@ extern "C" {
#endif
/**
* @name Return values for gcoap_obs_init()
* @name Return values for gcoap_obs_init()
* @{
*/
#define GCOAP_OBS_INIT_OK (0)
#define GCOAP_OBS_INIT_ERR (-1)
#define GCOAP_OBS_INIT_UNUSED (-2)
#define GCOAP_OBS_INIT_ERR (-1)
#define GCOAP_OBS_INIT_UNUSED (-2)
/** @} */
/**
* @brief A modular collection of resources for a server
* @brief A modular collection of resources for a server
*/
typedef struct gcoap_listener {
coap_resource_t *resources; /**< First element in the array of
@ -359,15 +389,15 @@ typedef struct gcoap_listener {
} gcoap_listener_t;
/**
* @brief Handler function for a server response, including the state for the
* originating request.
* @brief Handler function for a server response, including the state for the
* originating request
*
* If request timed out, the packet header is for the request.
*/
typedef void (*gcoap_resp_handler_t)(unsigned req_state, coap_pkt_t* pdu);
/**
* @brief Memo to handle a response for a request
* @brief Memo to handle a response for a request
*/
typedef struct {
unsigned state; /**< State of this memo, a GCOAP_MEMO... */
@ -378,7 +408,9 @@ typedef struct {
msg_t timeout_msg; /**< For response timer */
} gcoap_request_memo_t;
/** @brief Memo for Observe registration and notifications */
/**
* @brief Memo for Observe registration and notifications
*/
typedef struct {
sock_udp_ep_t *observer; /**< Client endpoint; unused if null */
coap_resource_t *resource; /**< Entity being observed */
@ -387,7 +419,7 @@ typedef struct {
} gcoap_observe_memo_t;
/**
* @brief Container for the state of gcoap itself
* @brief Container for the state of gcoap itself
*/
typedef struct {
gcoap_listener_t *listeners; /**< List of registered listeners */
@ -404,7 +436,7 @@ typedef struct {
} gcoap_state_t;
/**
* @brief Initializes the gcoap thread and device.
* @brief Initializes the gcoap thread and device
*
* Must call once before first use.
*
@ -415,58 +447,57 @@ typedef struct {
kernel_pid_t gcoap_init(void);
/**
* @brief Starts listening for resource paths.
* @brief Starts listening for resource paths
*
* @param listener Listener containing the resources.
* @param[in] listener Listener containing the resources.
*/
void gcoap_register_listener(gcoap_listener_t *listener);
/**
* @brief Initializes a CoAP request PDU on a buffer.
* @brief Initializes a CoAP request PDU on a buffer.
*
* @param[in] pdu Request metadata
* @param[in] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] code Request code
* @param[in] path Resource path
* @param[out] pdu Request metadata
* @param[out] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] code Request code: GCOAP_[GET|POST|PUT|DELETE]
* @param[in] path Resource path, *must* start with '/'
*
* @return 0 on success
* @return < 0 on error
* @return 0 on success
* @return < 0 on error
*/
int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, unsigned code,
char *path);
int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
unsigned code, char *path);
/**
* @brief Finishes formatting a CoAP PDU after the payload has been written.
* @brief Finishes formatting a CoAP PDU after the payload has been written
*
* Assumes the PDU has been initialized with gcoap_req_init() or
* gcoap_resp_init().
*
* @param[in] pdu Request metadata
* @param[in] payload_len Length of the payload, or 0 if none
* @param[in] format Format code for the payload; use COAP_FORMAT_NONE if not
* specified
* @param[in,out] pdu Request metadata
* @param[in] payload_len Length of the payload, or 0 if none
* @param[in] format Format code for the payload; use COAP_FORMAT_NONE if
* not specified
*
* @return size of the PDU
* @return < 0 on error
* @return size of the PDU
* @return < 0 on error
*/
ssize_t gcoap_finish(coap_pkt_t *pdu, size_t payload_len, unsigned format);
/**
* @brief Writes a complete CoAP request PDU when there is not a payload.
* @brief Writes a complete CoAP request PDU when there is not a payload
*
* @param[in] pdu Request metadata
* @param[in] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] code Request code
* @param[in] path Resource path
* @param[in,out] pdu Request metadata
* @param[in,out] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] code Request code: GCOAP_[GET|POST|PUT|DELETE]
* @param[in] path Resource path, *must* start with '/'
*
* @return size of the PDU within the buffer
* @return < 0 on error
* @return size of the PDU within the buffer
* @return < 0 on error
*/
static inline ssize_t gcoap_request(coap_pkt_t *pdu, uint8_t *buf, size_t len,
unsigned code,
char *path)
unsigned code, char *path)
{
return (gcoap_req_init(pdu, buf, len, code, path) == 0)
? gcoap_finish(pdu, 0, COAP_FORMAT_NONE)
@ -474,65 +505,65 @@ static inline ssize_t gcoap_request(coap_pkt_t *pdu, uint8_t *buf, size_t len,
}
/**
* @brief Sends a buffer containing a CoAP request to the provided endpoint.
* @brief Sends a buffer containing a CoAP request to the provided endpoint
*
* @param[in] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] remote Destination for the packet
* @param[in] resp_handler Callback when response received
* @param[in] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] remote Destination for the packet
* @param[in] resp_handler Callback when response received
*
* @return length of the packet
* @return 0 if cannot send
* @return length of the packet
* @return 0 if cannot send
*/
size_t gcoap_req_send2(const uint8_t *buf, size_t len,
const sock_udp_ep_t *remote,
gcoap_resp_handler_t resp_handler);
/**
* @brief Sends a buffer containing a CoAP request to the provided host/port.
* @brief Sends a buffer containing a CoAP request to the provided host/port
*
* @deprecated Please use @ref gcoap_req_send2() instead
*
* @param[in] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] addr Destination for the packet
* @param[in] port Port at the destination
* @param[in] resp_handler Callback when response received
* @param[in] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] addr Destination for the packet
* @param[in] port Port at the destination
* @param[in] resp_handler Callback when response received
*
* @return length of the packet
* @return 0 if cannot send
* @return length of the packet
* @return 0 if cannot send
*/
size_t gcoap_req_send(const uint8_t *buf, size_t len, const ipv6_addr_t *addr,
uint16_t port, gcoap_resp_handler_t resp_handler);
/**
* @brief Initializes a CoAP response packet on a buffer.
* @brief Initializes a CoAP response packet on a buffer
*
* Initializes payload location within the buffer based on packet setup.
*
* @param[in] pdu Response metadata
* @param[in] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] code Response code
* @param[out] pdu Response metadata
* @param[in] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] code Response code
*
* @return 0 on success
* @return < 0 on error
* @return 0 on success
* @return < 0 on error
*/
int gcoap_resp_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, unsigned code);
/**
* @brief Writes a complete CoAP response PDU when there is no payload.
* @brief Writes a complete CoAP response PDU when there is no payload
*
* @param[in] pdu Response metadata
* @param[in] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] code Response code
* @param[out] pdu Response metadata
* @param[out] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] code Response code
*
* @return size of the PDU within the buffer
* @return < 0 on error
* @return size of the PDU within the buffer
* @return < 0 on error
*/
static inline ssize_t gcoap_response(coap_pkt_t *pdu, uint8_t *buf, size_t len,
unsigned code)
static inline ssize_t gcoap_response(coap_pkt_t *pdu, uint8_t *buf,
size_t len, unsigned code)
{
return (gcoap_resp_init(pdu, buf, len, code) == 0)
? gcoap_finish(pdu, 0, COAP_FORMAT_NONE)
@ -540,26 +571,26 @@ static inline ssize_t gcoap_response(coap_pkt_t *pdu, uint8_t *buf, size_t len,
}
/**
* @brief Initializes a CoAP Observe notification packet on a buffer, for the
* observer registered for a resource.
* @brief Initializes a CoAP Observe notification packet on a buffer, for the
* observer registered for a resource
*
* First verifies that an observer has been registered for the resource.
*
* @param[in] pdu Notification metadata
* @param[in] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] resource Resource for the notification
* @param[out] pdu Notification metadata
* @param[out] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] resource Resource for the notification
*
* @return GCOAP_OBS_INIT_OK on success
* @return GCOAP_OBS_INIT_ERR on error
* @return GCOAP_OBS_INIT_UNUSED if no observer for resource
* @return GCOAP_OBS_INIT_OK on success
* @return GCOAP_OBS_INIT_ERR on error
* @return GCOAP_OBS_INIT_UNUSED if no observer for resource
*/
int gcoap_obs_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
const coap_resource_t *resource);
const coap_resource_t *resource);
/**
* @brief Sends a buffer containing a CoAP Observe notification to the
* observer registered for a resource.
* @brief Sends a buffer containing a CoAP Observe notification to the
* observer registered for a resource
*
* Assumes a single observer for a resource.
*
@ -567,18 +598,18 @@ int gcoap_obs_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
* @param[in] len Length of the buffer
* @param[in] resource Resource to send
*
* @return length of the packet
* @return 0 if cannot send
* @return length of the packet
* @return 0 if cannot send
*/
size_t gcoap_obs_send(const uint8_t *buf, size_t len,
const coap_resource_t *resource);
/**
* @brief Provides important operational statistics.
* @brief Provides important operational statistics
*
* Useful for monitoring.
*
* @return count of unanswered requests
* @return count of unanswered requests
*/
uint8_t gcoap_op_state(void);

View File

@ -302,7 +302,7 @@ static void _find_resource(coap_pkt_t *pdu, coap_resource_t **resource_ptr,
static ssize_t _finish_pdu(coap_pkt_t *pdu, uint8_t *buf, size_t len)
{
ssize_t hdr_len = _write_options(pdu, buf, len);
DEBUG("gcoap: header length: %u\n", hdr_len);
DEBUG("gcoap: header length: %i\n", (int)hdr_len);
if (hdr_len > 0) {
/* move payload over unused space after options */
@ -452,6 +452,7 @@ static ssize_t _write_options(coap_pkt_t *pdu, uint8_t *buf, size_t len)
size_t url_len = strlen((char *)pdu->url);
if (url_len) {
if (pdu->url[0] != '/') {
DEBUG("gcoap: _write_options: path does not start with '/'\n");
return -EINVAL;
}
bufpos += coap_put_option_url(bufpos, last_optnum, (char *)&pdu->url[0]);