From fa815993ae45c113601218390024ac516102925f Mon Sep 17 00:00:00 2001 From: Ken Bannister Date: Wed, 9 Nov 2016 13:21:07 -0500 Subject: [PATCH 1/5] gcoap: Move from gnrc directory up to net directory --- Makefile.dep | 4 - sys/Makefile | 3 + sys/include/net/gcoap.h | 388 ++++++++++++++++++ sys/include/net/gnrc/coap.h | 373 +---------------- .../application_layer/coap/Makefile | 0 .../{gnrc => }/application_layer/coap/gcoap.c | 0 sys/net/gnrc/Makefile | 3 - 7 files changed, 395 insertions(+), 376 deletions(-) create mode 100644 sys/include/net/gcoap.h rename sys/net/{gnrc => }/application_layer/coap/Makefile (100%) rename sys/net/{gnrc => }/application_layer/coap/gcoap.c (100%) diff --git a/Makefile.dep b/Makefile.dep index 1c292a4448..178ecf0e31 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -96,10 +96,6 @@ ifneq (,$(filter gnrc_zep,$(USEMODULE))) USEMODULE += xtimer endif -ifneq (,$(filter gcoap,$(USEMODULE))) - USEMODULE += gnrc_udp -endif - ifneq (,$(filter gnrc_tftp,$(USEMODULE))) USEMODULE += gnrc_udp USEMODULE += xtimer diff --git a/sys/Makefile b/sys/Makefile index 99ddbaba88..7245192bf7 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -99,6 +99,9 @@ endif ifneq (,$(filter sema,$(USEMODULE))) DIRS += sema endif +ifneq (,$(filter gcoap,$(USEMODULE))) + DIRS += net/application_layer/coap +endif DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE}))) diff --git a/sys/include/net/gcoap.h b/sys/include/net/gcoap.h new file mode 100644 index 0000000000..6f73cb12b0 --- /dev/null +++ b/sys/include/net/gcoap.h @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2015-2016 Ken Bannister. All rights reserved. + * + * 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 + * directory for more details. + */ + +/** + * @defgroup net_gcoap CoAP + * @ingroup net + * @brief sock-based implementation of CoAP protocol, RFC 7252 + * + * ## Architecture ## + * Requests and responses are exchanged via an asynchronous RIOT message + * processing thread. Depends on nanocoap for base level structs and + * functionality. + * + * Uses a single UDP port for communication to support RFC 6282 compression. + * + * ## Server Operation ## + * + * gcoap listens for requests on GCOAP_PORT, 5683 by default. You can redefine + * this by uncommenting the appropriate lines in gcoap's make file. + * + * gcoap allows an application to specify a collection of request resource paths + * it wants to be notified about. Create an array of resources, coap_resource_t + * structs. Use gcoap_register_listener() at application startup to pass in + * these resources, wrapped in a gcoap_listener_t. + * + * gcoap itself defines a resource for `/.well-known/core` discovery, which + * lists all of the registered paths. + * + * ### Creating a response ### + * + * An application resource includes a callback function, a coap_handler_t. After + * reading the request, the callback must use one or two functions provided by + * gcoap to format the response, as described below. The callback *must* read + * the request thoroughly before calling the functions, because the response + * buffer likely reuses the request buffer. See `examples/gcoap/gcoap_cli.c` + * for a simple example of a callback. + * + * Here is the expected sequence for a callback function: + * + * Read request completely and parse request payload, if any. Use the + * coap_pkt_t _payload_ and _payload_len_ attributes. + * + * If there is a payload, follow the three steps below. + * + * -# Call gcoap_resp_init() to initialize the response. + * -# Write the request payload, starting at the updated _payload_ pointer + * in the coap_pkt_t. If some error occurs, return a negative errno + * code from the handler, and gcoap will send a server error (5.00). + * -# Call gcoap_finish() to complete the PDU after writing the payload, + * and return the result. gcoap will send the message. + * + * If no payload, call only gcoap_response() to write the full response. + * Alternatively, you still can use gcoap_resp_init() and gcoap_finish(), as + * described above. In fact, the gcoap_response() function is inline, and uses + * those two functions. + * + * ## Client Operation ## + * + * gcoap uses RIOT's asynchronous messaging facility to send and receive + * messages. So, client operation includes two phases: creating and sending a + * request, and handling the response aynchronously in a client supplied + * callback. See `examples/gcoap/gcoap_cli.c` for a simple example of sending + * a request and reading the response. + * + * ### Creating a request ### + * + * Here is the expected sequence for preparing and sending a request: + * + * Allocate a buffer and a coap_pkt_t for the request. + * + * If there is a payload, follow the three steps below. + * + * -# Call gcoap_req_init() to initialize the request. + * -# Write the request payload, starting at the updated _payload_ pointer + * in the coap_pkt_t. + * -# Call gcoap_finish(), which updates the packet for the payload. + * + * If no payload, call only gcoap_request() to write the full request. + * Alternatively, you still can use gcoap_req_init() and gcoap_finish(), + * as described above. The gcoap_request() function is inline, and uses those + * two functions. + * + * Finally, call gcoap_req_send() with the destination host and port, as well + * as a callback function for the host's response. + * + * ### Handling the response ### + * + * When gcoap receives the response to a request, it executes the callback from + * the request. gcoap also executes the callback when a response is not + * received within GCOAP_RESPONSE_TIMEOUT. + * + * Here is the expected sequence for handling a response in the callback. + * + * -# Test for a server response or timeout in the _req_state_ callback + * parameter. See the GCOAP_MEMO... constants. + * -# Test the response with coap_get_code_class() and coap_get_code_detail(). + * -# Test the response payload with the coap_pkt_t _payload_len_ and + * _content_type_ attributes. + * -# Read the payload, if any. + * + * ## Implementation Notes ## + * + * ### Building a packet ### + * + * The sequence and functions described above to build a request or response + * is designed to provide a relatively simple API for the user. + * + * The structure of a CoAP PDU requires that options are placed between the + * header and the payload. So, gcoap provides space in the buffer for them in + * the request/response ...init() function, and then writes them during + * gcoap_finish(). We trade some inefficiency/work in the buffer for + * simplicity for the user. + * + * ### Waiting for a response ### + * + * We take advantage of RIOT's GNRC stack by using an xtimer to wait for a + * response, so the gcoap thread does not block while waiting. The user is + * notified via the same callback whether the message is received or the wait + * times out. We track the response with an entry in the + * `_coap_state.open_reqs` array. + * + * @{ + * + * @file + * @brief gcoap definition + * + * @author Ken Bannister + */ + +#ifndef GCOAP_H +#define GCOAP_H + +#include "net/gnrc.h" +#include "net/gnrc/ipv6.h" +#include "net/gnrc/udp.h" +#include "nanocoap.h" +#include "xtimer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Size for module message queue */ +#define GCOAP_MSG_QUEUE_SIZE (4) + +/** @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. */ +#define GCOAP_PDU_BUF_SIZE (128) + +/** + * @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. + * + * Accommodates Content-Format. + */ +#define GCOAP_RESP_OPTIONS_BUF (8) + +/** @brief Maximum number of requests awaiting a response */ +#define GCOAP_REQ_WAITING_MAX (2) + +/** @brief Maximum length in bytes for a token */ +#define GCOAP_TOKENLEN_MAX (8) + +/** @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 */ +#ifndef GCOAP_TOKENLEN +#define GCOAP_TOKENLEN (2) +#endif + +/** @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 + * @{ + */ +#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 Default time to wait for a non-confirmable response, in usec + * + * Set to 0 to disable timeout. + */ +#define GCOAP_NON_TIMEOUT (5000000U) + +/** @brief Identifies a gcoap-specific timeout IPC message */ +#define GCOAP_NETAPI_MSG_TYPE_TIMEOUT (0x1501) + +/** + * @brief A modular collection of resources for a server + */ +typedef struct gcoap_listener { + coap_resource_t *resources; /**< First element in the array of resources; + must order alphabetically */ + size_t resources_len; /**< Length of array */ + struct gcoap_listener *next; /**< Next listener in list */ +} gcoap_listener_t; + +/** + * @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 + */ +typedef struct { + unsigned state; /**< State of this memo, a GCOAP_MEMO... */ + uint8_t hdr_buf[GCOAP_HEADER_MAXLEN]; + /**< Stores a copy of the request header */ + gcoap_resp_handler_t resp_handler; /**< Callback for the response */ + xtimer_t response_timer; /**< Limits wait for response */ + msg_t timeout_msg; /**< For response timer */ +} gcoap_request_memo_t; + +/** + * @brief Container for the state of gcoap itself + */ +typedef struct { + gnrc_netreg_entry_t netreg_port; /**< Registration for IP port */ + gcoap_listener_t *listeners; /**< List of registered listeners */ + gcoap_request_memo_t open_reqs[GCOAP_REQ_WAITING_MAX]; + /**< Storage for open requests; if first + byte of an entry is zero, the entry + is available */ + uint16_t last_message_id; /**< Last message ID used */ +} gcoap_state_t; + +/** + * @brief Initializes the gcoap thread and device. + * + * Must call once before first use. + * + * @return PID of the gcoap thread on success. + * @return -EEXIST, if thread already has been created. + * @return -EINVAL, if the IP port already is in use. + */ +kernel_pid_t gcoap_init(void); + +/** + * @brief Starts listening for resource paths. + * + * @param listener Listener containing the resources. + */ +void gcoap_register_listener(gcoap_listener_t *listener); + +/** + * @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 + * + * @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); + +/** + * @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 + * + * @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. + * + * @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 + * + * @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) +{ + return (gcoap_req_init(pdu, buf, len, code, path) == 0) + ? gcoap_finish(pdu, 0, COAP_FORMAT_NONE) + : -1; +} + +/** + * @brief Sends a buffer containing a CoAP request to the provided host/port. + * + * @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 + */ +size_t gcoap_req_send(uint8_t *buf, size_t len, ipv6_addr_t *addr, uint16_t port, + gcoap_resp_handler_t resp_handler); + +/** + * @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 + * + * @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. + * + * @param[in] pdu Response metadata + * @param[in] 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 + */ +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) + : -1; +} + +/** + * @brief Provides important operational statistics. + * + * Useful for monitoring. + * + * @param[out] open_reqs Count of unanswered requests + */ +void gcoap_op_state(uint8_t *open_reqs); + +#ifdef __cplusplus +} +#endif + +#endif /* GCOAP_H */ +/** @} */ diff --git a/sys/include/net/gnrc/coap.h b/sys/include/net/gnrc/coap.h index b45d5ab511..33022a131f 100644 --- a/sys/include/net/gnrc/coap.h +++ b/sys/include/net/gnrc/coap.h @@ -7,382 +7,17 @@ */ /** - * @defgroup net_gnrc_coap CoAP - * @ingroup net_gnrc - * @brief GNRC implementation of CoAP protocol, RFC 7252 - * - * ## Architecture ## - * Requests and responses are exchanged via an asynchronous RIOT message - * processing thread. Depends on nanocoap for base level structs and - * functionality. - * - * Uses a single UDP port for communication to support RFC 6282 compression. - * - * ## Server Operation ## - * - * gcoap listens for requests on GCOAP_PORT, 5683 by default. You can redefine - * this by uncommenting the appropriate lines in gcoap's make file. - * - * gcoap allows an application to specify a collection of request resource paths - * it wants to be notified about. Create an array of resources, coap_resource_t - * structs. Use gcoap_register_listener() at application startup to pass in - * these resources, wrapped in a gcoap_listener_t. - * - * gcoap itself defines a resource for `/.well-known/core` discovery, which - * lists all of the registered paths. - * - * ### Creating a response ### - * - * An application resource includes a callback function, a coap_handler_t. After - * reading the request, the callback must use one or two functions provided by - * gcoap to format the response, as described below. The callback *must* read - * the request thoroughly before calling the functions, because the response - * buffer likely reuses the request buffer. See `examples/gcoap/gcoap_cli.c` - * for a simple example of a callback. - * - * Here is the expected sequence for a callback function: - * - * Read request completely and parse request payload, if any. Use the - * coap_pkt_t _payload_ and _payload_len_ attributes. - * - * If there is a payload, follow the three steps below. - * - * -# Call gcoap_resp_init() to initialize the response. - * -# Write the request payload, starting at the updated _payload_ pointer - * in the coap_pkt_t. If some error occurs, return a negative errno - * code from the handler, and gcoap will send a server error (5.00). - * -# Call gcoap_finish() to complete the PDU after writing the payload, - * and return the result. gcoap will send the message. - * - * If no payload, call only gcoap_response() to write the full response. - * Alternatively, you still can use gcoap_resp_init() and gcoap_finish(), as - * described above. In fact, the gcoap_response() function is inline, and uses - * those two functions. - * - * ## Client Operation ## - * - * gcoap uses RIOT's asynchronous messaging facility to send and receive - * messages. So, client operation includes two phases: creating and sending a - * request, and handling the response aynchronously in a client supplied - * callback. See `examples/gcoap/gcoap_cli.c` for a simple example of sending - * a request and reading the response. - * - * ### Creating a request ### - * - * Here is the expected sequence for preparing and sending a request: - * - * Allocate a buffer and a coap_pkt_t for the request. - * - * If there is a payload, follow the three steps below. - * - * -# Call gcoap_req_init() to initialize the request. - * -# Write the request payload, starting at the updated _payload_ pointer - * in the coap_pkt_t. - * -# Call gcoap_finish(), which updates the packet for the payload. - * - * If no payload, call only gcoap_request() to write the full request. - * Alternatively, you still can use gcoap_req_init() and gcoap_finish(), - * as described above. The gcoap_request() function is inline, and uses those - * two functions. - * - * Finally, call gcoap_req_send() with the destination host and port, as well - * as a callback function for the host's response. - * - * ### Handling the response ### - * - * When gcoap receives the response to a request, it executes the callback from - * the request. gcoap also executes the callback when a response is not - * received within GCOAP_RESPONSE_TIMEOUT. - * - * Here is the expected sequence for handling a response in the callback. - * - * -# Test for a server response or timeout in the _req_state_ callback - * parameter. See the GCOAP_MEMO... constants. - * -# Test the response with coap_get_code_class() and coap_get_code_detail(). - * -# Test the response payload with the coap_pkt_t _payload_len_ and - * _content_type_ attributes. - * -# Read the payload, if any. - * - * ## Implementation Notes ## - * - * ### Building a packet ### - * - * The sequence and functions described above to build a request or response - * is designed to provide a relatively simple API for the user. - * - * The structure of a CoAP PDU requires that options are placed between the - * header and the payload. So, gcoap provides space in the buffer for them in - * the request/response ...init() function, and then writes them during - * gcoap_finish(). We trade some inefficiency/work in the buffer for - * simplicity for the user. - * - * ### Waiting for a response ### - * - * We take advantage of RIOT's GNRC stack by using an xtimer to wait for a - * response, so the gcoap thread does not block while waiting. The user is - * notified via the same callback whether the message is received or the wait - * times out. We track the response with an entry in the - * `_coap_state.open_reqs` array. + * @ingroup net_gcoap + * @brief Adapter for migration of GNRC-based gcoap to sock-based gcoap + * @deprecated Use net/gcoap.h instead. * * @{ * * @file - * @brief gcoap definition * * @author Ken Bannister */ -#ifndef GCOAP_H -#define GCOAP_H +#include "net/gcoap.h" -#include "net/gnrc.h" -#include "net/gnrc/ipv6.h" -#include "net/gnrc/udp.h" -#include "nanocoap.h" -#include "xtimer.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @brief Size for module message queue */ -#define GCOAP_MSG_QUEUE_SIZE (4) - -/** @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. */ -#define GCOAP_PDU_BUF_SIZE (128) - -/** - * @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. - * - * Accommodates Content-Format. - */ -#define GCOAP_RESP_OPTIONS_BUF (8) - -/** @brief Maximum number of requests awaiting a response */ -#define GCOAP_REQ_WAITING_MAX (2) - -/** @brief Maximum length in bytes for a token */ -#define GCOAP_TOKENLEN_MAX (8) - -/** @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 */ -#ifndef GCOAP_TOKENLEN -#define GCOAP_TOKENLEN (2) -#endif - -/** @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 - * @{ - */ -#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 Default time to wait for a non-confirmable response, in usec - * - * Set to 0 to disable timeout. - */ -#define GCOAP_NON_TIMEOUT (5000000U) - -/** @brief Identifies a gcoap-specific timeout IPC message */ -#define GCOAP_NETAPI_MSG_TYPE_TIMEOUT (0x1501) - -/** - * @brief A modular collection of resources for a server - */ -typedef struct gcoap_listener { - coap_resource_t *resources; /**< First element in the array of resources; - must order alphabetically */ - size_t resources_len; /**< Length of array */ - struct gcoap_listener *next; /**< Next listener in list */ -} gcoap_listener_t; - -/** - * @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 - */ -typedef struct { - unsigned state; /**< State of this memo, a GCOAP_MEMO... */ - uint8_t hdr_buf[GCOAP_HEADER_MAXLEN]; - /**< Stores a copy of the request header */ - gcoap_resp_handler_t resp_handler; /**< Callback for the response */ - xtimer_t response_timer; /**< Limits wait for response */ - msg_t timeout_msg; /**< For response timer */ -} gcoap_request_memo_t; - -/** - * @brief Container for the state of gcoap itself - */ -typedef struct { - gnrc_netreg_entry_t netreg_port; /**< Registration for IP port */ - gcoap_listener_t *listeners; /**< List of registered listeners */ - gcoap_request_memo_t open_reqs[GCOAP_REQ_WAITING_MAX]; - /**< Storage for open requests; if first - byte of an entry is zero, the entry - is available */ - uint16_t last_message_id; /**< Last message ID used */ -} gcoap_state_t; - -/** - * @brief Initializes the gcoap thread and device. - * - * Must call once before first use. - * - * @return PID of the gcoap thread on success. - * @return -EEXIST, if thread already has been created. - * @return -EINVAL, if the IP port already is in use. - */ -kernel_pid_t gcoap_init(void); - -/** - * @brief Starts listening for resource paths. - * - * @param listener Listener containing the resources. - */ -void gcoap_register_listener(gcoap_listener_t *listener); - -/** - * @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 - * - * @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); - -/** - * @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 - * - * @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. - * - * @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 - * - * @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) -{ - return (gcoap_req_init(pdu, buf, len, code, path) == 0) - ? gcoap_finish(pdu, 0, COAP_FORMAT_NONE) - : -1; -} - -/** - * @brief Sends a buffer containing a CoAP request to the provided host/port. - * - * @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 - */ -size_t gcoap_req_send(uint8_t *buf, size_t len, ipv6_addr_t *addr, uint16_t port, - gcoap_resp_handler_t resp_handler); - -/** - * @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 - * - * @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. - * - * @param[in] pdu Response metadata - * @param[in] 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 - */ -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) - : -1; -} - -/** - * @brief Provides important operational statistics. - * - * Useful for monitoring. - * - * @param[out] open_reqs Count of unanswered requests - */ -void gcoap_op_state(uint8_t *open_reqs); - -#ifdef __cplusplus -} -#endif - -#endif /* GCOAP_H */ /** @} */ diff --git a/sys/net/gnrc/application_layer/coap/Makefile b/sys/net/application_layer/coap/Makefile similarity index 100% rename from sys/net/gnrc/application_layer/coap/Makefile rename to sys/net/application_layer/coap/Makefile diff --git a/sys/net/gnrc/application_layer/coap/gcoap.c b/sys/net/application_layer/coap/gcoap.c similarity index 100% rename from sys/net/gnrc/application_layer/coap/gcoap.c rename to sys/net/application_layer/coap/gcoap.c diff --git a/sys/net/gnrc/Makefile b/sys/net/gnrc/Makefile index a974618c5e..ba3781bdb6 100644 --- a/sys/net/gnrc/Makefile +++ b/sys/net/gnrc/Makefile @@ -136,8 +136,5 @@ endif ifneq (,$(filter gnrc_tftp,$(USEMODULE))) DIRS += application_layer/tftp endif -ifneq (,$(filter gcoap,$(USEMODULE))) - DIRS += application_layer/coap -endif include $(RIOTBASE)/Makefile.base From af1eca907fd90339a9ae58839176200013a25d55 Mon Sep 17 00:00:00 2001 From: Ken Bannister Date: Thu, 17 Nov 2016 00:01:15 -0500 Subject: [PATCH 2/5] gcoap: Rebase messaging on sock API --- sys/include/net/gcoap.h | 77 +++++--- sys/net/application_layer/coap/gcoap.c | 242 +++++++++---------------- 2 files changed, 143 insertions(+), 176 deletions(-) diff --git a/sys/include/net/gcoap.h b/sys/include/net/gcoap.h index 6f73cb12b0..097fd4812c 100644 --- a/sys/include/net/gcoap.h +++ b/sys/include/net/gcoap.h @@ -9,14 +9,21 @@ /** * @defgroup net_gcoap CoAP * @ingroup net - * @brief sock-based implementation of CoAP protocol, RFC 7252 + * @brief High-level interface to CoAP messaging * - * ## Architecture ## - * Requests and responses are exchanged via an asynchronous RIOT message - * processing thread. Depends on nanocoap for base level structs and - * functionality. + * gcoap provides a high-level interface for writing CoAP messages via RIOT's + * sock networking API. gcoap internalizes network event processing so an + * application only needs to focus on request/response handling. For a server, + * gcoap accepts a list of resource paths with callbacks for writing the + * response. For a client, gcoap provides a function to send a request, with a + * callback for reading the server response. Generation of the request or + * response requires from one to three well-defined steps, depending on + * inclusion of a payload. * - * Uses a single UDP port for communication to support RFC 6282 compression. + * gcoap allocates a RIOT message processing thread, so a single instance can + * serve multiple applications. This approach also means gcoap uses a single UDP + * port, which supports RFC 6282 compression. Internally, gcoap depends on the + * nanocoap package for base level structs and functionality. * * ## Server Operation ## * @@ -61,11 +68,10 @@ * * ## Client Operation ## * - * gcoap uses RIOT's asynchronous messaging facility to send and receive - * messages. So, client operation includes two phases: creating and sending a - * request, and handling the response aynchronously in a client supplied - * callback. See `examples/gcoap/gcoap_cli.c` for a simple example of sending - * a request and reading the response. + * Client operation includes two phases: creating and sending a request, and + * handling the response aynchronously in a client supplied callback. See + * `examples/gcoap/gcoap_cli.c` for a simple example of sending a request and + * reading the response. * * ### Creating a request ### * @@ -85,8 +91,8 @@ * as described above. The gcoap_request() function is inline, and uses those * two functions. * - * Finally, call gcoap_req_send() with the destination host and port, as well - * as a callback function for the host's response. + * Finally, call gcoap_req_send2() for the destination endpoint, as well as a + * callback function for the host's response. * * ### Handling the response ### * @@ -114,13 +120,13 @@ * header and the payload. So, gcoap provides space in the buffer for them in * the request/response ...init() function, and then writes them during * gcoap_finish(). We trade some inefficiency/work in the buffer for - * simplicity for the user. + * simplicity in the API. * * ### Waiting for a response ### * - * We take advantage of RIOT's GNRC stack by using an xtimer to wait for a - * response, so the gcoap thread does not block while waiting. The user is - * notified via the same callback whether the message is received or the wait + * We take advantage of RIOT's asynchronous messaging by using an xtimer to wait + * for a response, so the gcoap thread does not block while waiting. The user is + * notified via the same callback, whether the message is received or the wait * times out. We track the response with an entry in the * `_coap_state.open_reqs` array. * @@ -135,9 +141,7 @@ #ifndef GCOAP_H #define GCOAP_H -#include "net/gnrc.h" -#include "net/gnrc/ipv6.h" -#include "net/gnrc/udp.h" +#include "net/sock/udp.h" #include "nanocoap.h" #include "xtimer.h" @@ -199,15 +203,27 @@ extern "C" { #define GCOAP_MEMO_ERR (4) /**< Error processing response packet */ /** @} */ +/** @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 * * Set to 0 to disable timeout. */ #define GCOAP_NON_TIMEOUT (5000000U) -/** @brief Identifies a gcoap-specific timeout IPC message */ -#define GCOAP_NETAPI_MSG_TYPE_TIMEOUT (0x1501) +/** @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. + * + * Allows the event loop to process IPC messages. + */ +#define GCOAP_MSG_TYPE_INTR (0x1502) /** * @brief A modular collection of resources for a server @@ -243,7 +259,6 @@ typedef struct { * @brief Container for the state of gcoap itself */ typedef struct { - gnrc_netreg_entry_t netreg_port; /**< Registration for IP port */ gcoap_listener_t *listeners; /**< List of registered listeners */ gcoap_request_memo_t open_reqs[GCOAP_REQ_WAITING_MAX]; /**< Storage for open requests; if first @@ -322,9 +337,25 @@ static inline ssize_t gcoap_request(coap_pkt_t *pdu, uint8_t *buf, size_t len, : -1; } +/** + * @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 + * + * @return length of the packet + * @return 0 if cannot send + */ +size_t gcoap_req_send2(uint8_t *buf, size_t len, sock_udp_ep_t *remote, + gcoap_resp_handler_t resp_handler); + /** * @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 diff --git a/sys/net/application_layer/coap/gcoap.c b/sys/net/application_layer/coap/gcoap.c index a2e055f330..a64586341f 100644 --- a/sys/net/application_layer/coap/gcoap.c +++ b/sys/net/application_layer/coap/gcoap.c @@ -7,7 +7,7 @@ */ /** - * @ingroup net_gnrc_coap + * @ingroup net_gcoap * @{ * * @file @@ -19,7 +19,7 @@ */ #include -#include "net/gnrc/coap.h" +#include "net/gcoap.h" #include "random.h" #include "thread.h" @@ -31,14 +31,11 @@ /* Internal functions */ static void *_event_loop(void *arg); -static int _register_port(gnrc_netreg_entry_t *netreg_port, uint16_t port); -static void _receive(gnrc_pktsnip_t *pkt, ipv6_addr_t *src, uint16_t port); -static size_t _send(gnrc_pktsnip_t *coap_snip, ipv6_addr_t *addr, uint16_t port); +static void _listen(sock_udp_t *sock); static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len); static ssize_t _write_options(coap_pkt_t *pdu, uint8_t *buf, size_t len); static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len); static ssize_t _finish_pdu(coap_pkt_t *pdu, uint8_t *buf, size_t len); -static size_t _send_buf( uint8_t *buf, size_t len, ipv6_addr_t *src, uint16_t port); static void _expire_request(gcoap_request_memo_t *memo); static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu, uint8_t *buf, size_t len); @@ -55,97 +52,91 @@ static gcoap_listener_t _default_listener = { }; static gcoap_state_t _coap_state = { - .netreg_port = GNRC_NETREG_ENTRY_INIT_PID(0, KERNEL_PID_UNDEF), .listeners = &_default_listener, }; static kernel_pid_t _pid = KERNEL_PID_UNDEF; static char _msg_stack[GCOAP_STACK_SIZE]; +static sock_udp_t _sock; /* Event/Message loop for gcoap _pid thread. */ static void *_event_loop(void *arg) { msg_t msg_rcvd, msg_queue[GCOAP_MSG_QUEUE_SIZE]; - gnrc_pktsnip_t *pkt, *udp_snip, *ipv6_snip; - ipv6_addr_t *src_addr; - uint16_t port; - (void)arg; + msg_init_queue(msg_queue, GCOAP_MSG_QUEUE_SIZE); - while (1) { - msg_receive(&msg_rcvd); + sock_udp_ep_t local; + memset(&local, 0, sizeof(sock_udp_ep_t)); + local.family = AF_INET6; + local.netif = SOCK_ADDR_ANY_NETIF; + local.port = GCOAP_PORT; - switch (msg_rcvd.type) { - case GNRC_NETAPI_MSG_TYPE_RCV: - /* find client from UDP destination port */ - DEBUG("coap: GNRC_NETAPI_MSG_TYPE_RCV\n"); - pkt = (gnrc_pktsnip_t *)msg_rcvd.content.ptr; - if (pkt->type != GNRC_NETTYPE_UNDEF) { - gnrc_pktbuf_release(pkt); - break; - } - udp_snip = pkt->next; - if (udp_snip->type != GNRC_NETTYPE_UDP) { - gnrc_pktbuf_release(pkt); - break; - } - - /* read source port and address */ - port = byteorder_ntohs(((udp_hdr_t *)udp_snip->data)->src_port); - - LL_SEARCH_SCALAR(udp_snip, ipv6_snip, type, GNRC_NETTYPE_IPV6); - assert(ipv6_snip != NULL); - src_addr = &((ipv6_hdr_t *)ipv6_snip->data)->src; - - _receive(pkt, src_addr, port); - break; - - case GCOAP_NETAPI_MSG_TYPE_TIMEOUT: - _expire_request((gcoap_request_memo_t *)msg_rcvd.content.ptr); - break; - - default: - break; - } + int res = sock_udp_create(&_sock, &local, NULL, 0); + if (res < 0) { + DEBUG("gcoap: cannot create sock: %d\n", res); + return 0; } + + while(1) { + res = msg_try_receive(&msg_rcvd); + + if (res > 0) { + switch (msg_rcvd.type) { + case GCOAP_MSG_TYPE_TIMEOUT: + _expire_request((gcoap_request_memo_t *)msg_rcvd.content.ptr); + break; + case GCOAP_MSG_TYPE_INTR: + /* next _listen() timeout will account for open requests */ + break; + default: + break; + } + } + + _listen(&_sock); + } + return 0; } -/* Handles incoming network IPC message. */ -static void _receive(gnrc_pktsnip_t *pkt, ipv6_addr_t *src, uint16_t port) +/* Listen for an incoming CoAP message. */ +static void _listen(sock_udp_t *sock) { coap_pkt_t pdu; uint8_t buf[GCOAP_PDU_BUF_SIZE]; - size_t pdu_len = 0; + sock_udp_ep_t remote; gcoap_request_memo_t *memo = NULL; + uint8_t open_reqs; - /* If too big, handle below based on request vs. response */ - size_t pkt_size = (pkt->size > sizeof(buf)) - ? sizeof(buf) : pkt->size; + gcoap_op_state(&open_reqs); - /* Copy request into temporary buffer, and parse it as CoAP. */ - memcpy(buf, pkt->data, pkt_size); + ssize_t res = sock_udp_recv(sock, buf, sizeof(buf), + open_reqs > 0 ? GCOAP_RECV_TIMEOUT : SOCK_NO_TIMEOUT, + &remote); + if (res <= 0) { +#if ENABLE_DEBUG + if (res < 0 && res != -ETIMEDOUT) { + DEBUG("gcoap: udp recv failure: %d\n", res); + } +#endif + return; + } - int result = coap_parse(&pdu, buf, pkt_size); - if (result < 0) { - DEBUG("gcoap: parse failure: %d\n", result); + res = coap_parse(&pdu, buf, res); + if (res < 0) { + DEBUG("gcoap: parse failure: %d\n", res); /* If a response, can't clear memo, but it will timeout later. */ - goto exit; + return; } /* incoming request */ if (coap_get_code_class(&pdu) == COAP_CLASS_REQ) { - if (pkt->size > sizeof(buf)) { - DEBUG("gcoap: request too big: %u\n", pkt->size); - pdu_len = gcoap_response(&pdu, buf, sizeof(buf), - COAP_CODE_REQUEST_ENTITY_TOO_LARGE); - } else { - pdu_len = _handle_req(&pdu, buf, sizeof(buf)); - } + size_t pdu_len = _handle_req(&pdu, buf, sizeof(buf)); if (pdu_len > 0) { - _send_buf(buf, pdu_len, src, port); + sock_udp_send(sock, buf, pdu_len, &remote); } } /* incoming response */ @@ -153,17 +144,10 @@ static void _receive(gnrc_pktsnip_t *pkt, ipv6_addr_t *src, uint16_t port) _find_req_memo(&memo, &pdu, buf, sizeof(buf)); if (memo) { xtimer_remove(&memo->response_timer); - if (pkt->size > sizeof(buf)) { - memo->state = GCOAP_MEMO_ERR; - DEBUG("gcoap: response too big: %u\n", pkt->size); - } memo->resp_handler(memo->state, &pdu); memo->state = GCOAP_MEMO_UNUSED; } } - -exit: - gnrc_pktbuf_release(pkt); } /* @@ -296,77 +280,6 @@ static void _expire_request(gcoap_request_memo_t *memo) } } -/* Registers receive/send port with GNRC registry. */ -static int _register_port(gnrc_netreg_entry_t *netreg_port, uint16_t port) -{ - if (!gnrc_netreg_lookup(GNRC_NETTYPE_UDP, port)) { - gnrc_netreg_entry_init_pid(netreg_port, port, _pid); - gnrc_netreg_register(GNRC_NETTYPE_UDP, netreg_port); - DEBUG("coap: registered UDP port %" PRIu32 "\n", - netreg_port->demux_ctx); - return 0; - } - else { - return -EINVAL; - } -} - -/* - * Sends a CoAP message to the provided host/port. - * - * @return Length of the packet - * @return 0 if cannot send - */ -static size_t _send(gnrc_pktsnip_t *coap_snip, ipv6_addr_t *addr, uint16_t port) -{ - gnrc_pktsnip_t *udp, *ip; - size_t pktlen; - - /* allocate UDP header */ - udp = gnrc_udp_hdr_build(coap_snip, (uint16_t)_coap_state.netreg_port.demux_ctx, - port); - if (udp == NULL) { - DEBUG("gcoap: unable to allocate UDP header\n"); - gnrc_pktbuf_release(coap_snip); - return 0; - } - /* allocate IPv6 header */ - ip = gnrc_ipv6_hdr_build(udp, NULL, addr); - if (ip == NULL) { - DEBUG("gcoap: unable to allocate IPv6 header\n"); - gnrc_pktbuf_release(udp); - return 0; - } - pktlen = gnrc_pkt_len(ip); /* count length now; snips deallocated after send */ - - /* send message */ - if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_UDP, GNRC_NETREG_DEMUX_CTX_ALL, ip)) { - DEBUG("gcoap: unable to locate UDP thread\n"); - gnrc_pktbuf_release(ip); - return 0; - } - return pktlen; -} - -/* - * Copies the request/response buffer to a pktsnip and sends it. - * - * @return Length of the packet - * @return 0 if cannot send - */ -static size_t _send_buf(uint8_t *buf, size_t len, ipv6_addr_t *src, uint16_t port) -{ - gnrc_pktsnip_t *snip; - - snip = gnrc_pktbuf_add(NULL, NULL, len, GNRC_NETTYPE_UNDEF); - if (!snip) { - return 0; - } - memcpy(snip->data, buf, len); - - return _send(snip, src, port); -} - /* * Handler for /.well-known/core. Lists registered handlers, except for * /.well-known/core itself. @@ -456,10 +369,6 @@ kernel_pid_t gcoap_init(void) _pid = thread_create(_msg_stack, sizeof(_msg_stack), THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST, _event_loop, NULL, "coap"); - /* must establish pid first */ - if (_register_port(&_coap_state.netreg_port, GCOAP_PORT) < 0) { - return -EINVAL; - } /* Blank list of open requests so we know if an entry is available. */ memset(&_coap_state.open_reqs[0], 0, sizeof(_coap_state.open_reqs)); /* randomize initial value */ @@ -529,8 +438,23 @@ ssize_t gcoap_finish(coap_pkt_t *pdu, size_t payload_len, unsigned format) size_t gcoap_req_send(uint8_t *buf, size_t len, ipv6_addr_t *addr, uint16_t port, gcoap_resp_handler_t resp_handler) +{ + sock_udp_ep_t remote; + + remote.family = AF_INET6; + remote.netif = SOCK_ADDR_ANY_NETIF; + remote.port = port; + + memcpy(&remote.addr.ipv6[0], &addr->u8[0], sizeof(addr->u8)); + + return gcoap_req_send2(buf, len, &remote, resp_handler); +} + +size_t gcoap_req_send2(uint8_t *buf, size_t len, sock_udp_ep_t *remote, + gcoap_resp_handler_t resp_handler) { gcoap_request_memo_t *memo = NULL; + assert(remote != NULL); assert(resp_handler != NULL); /* Find empty slot in list of open requests. */ @@ -545,16 +469,28 @@ size_t gcoap_req_send(uint8_t *buf, size_t len, ipv6_addr_t *addr, uint16_t port memcpy(&memo->hdr_buf[0], buf, GCOAP_HEADER_MAXLEN); memo->resp_handler = resp_handler; - size_t res = _send_buf(buf, len, addr, port); + size_t res = sock_udp_send(&_sock, buf, len, remote); + if (res && (GCOAP_NON_TIMEOUT > 0)) { - /* start response wait timer */ - memo->timeout_msg.type = GCOAP_NETAPI_MSG_TYPE_TIMEOUT; - memo->timeout_msg.content.ptr = (char *)memo; - xtimer_set_msg(&memo->response_timer, GCOAP_NON_TIMEOUT, - &memo->timeout_msg, _pid); + /* interrupt sock listening (to set a listen timeout) */ + msg_t mbox_msg; + mbox_msg.type = GCOAP_MSG_TYPE_INTR; + mbox_msg.content.value = 0; + if (mbox_try_put(&_sock.reg.mbox, &mbox_msg)) { + /* start response wait timer */ + memo->timeout_msg.type = GCOAP_MSG_TYPE_TIMEOUT; + memo->timeout_msg.content.ptr = (char *)memo; + xtimer_set_msg(&memo->response_timer, GCOAP_NON_TIMEOUT, + &memo->timeout_msg, _pid); + } + else { + memo->state = GCOAP_MEMO_UNUSED; + DEBUG("gcoap: can't wake up mbox; no timeout for msg\n"); + } } else if (!res) { memo->state = GCOAP_MEMO_UNUSED; + DEBUG("gcoap: sock send failed: %d\n", res); } return res; } else { From e10e57959334f797df45ac83f31a27e6bdc1dbbb Mon Sep 17 00:00:00 2001 From: Ken Bannister Date: Thu, 17 Nov 2016 00:03:08 -0500 Subject: [PATCH 3/5] gcoap: Update CLI example for rebase on sock --- examples/gcoap/Makefile | 5 ++--- examples/gcoap/Makefile.slip | 5 ++--- examples/gcoap/README.md | 2 +- examples/gcoap/gcoap_cli.c | 13 +++++++++---- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/examples/gcoap/Makefile b/examples/gcoap/Makefile index e59ed27b13..8897ddeaaa 100644 --- a/examples/gcoap/Makefile +++ b/examples/gcoap/Makefile @@ -1,4 +1,4 @@ -# Default Makefile, for host native networking +# Default Makefile, for host native GNRC-based networking # name of your application APPLICATION = gcoap @@ -29,8 +29,6 @@ BOARD_BLACKLIST := nrf52dk USEPKG += nanocoap # Required by nanocoap, but only due to issue #5959. USEMODULE += posix -# Required by nanocoap to compile nanocoap_sock. -USEMODULE += gnrc_sock_udp # Include packages that pull up and auto-init the link layer. # NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present @@ -38,6 +36,7 @@ USEMODULE += gnrc_netdev_default USEMODULE += auto_init_gnrc_netif # Specify the mandatory networking modules USEMODULE += gnrc_ipv6_default +USEMODULE += gnrc_sock_udp USEMODULE += gcoap # Additional networking modules that can be dropped if not needed USEMODULE += gnrc_icmpv6_echo diff --git a/examples/gcoap/Makefile.slip b/examples/gcoap/Makefile.slip index abd5771863..8cb8a5fec1 100644 --- a/examples/gcoap/Makefile.slip +++ b/examples/gcoap/Makefile.slip @@ -1,4 +1,4 @@ -# Border router Makefile for SLIP based networking +# Border router Makefile for GNRC and SLIP based networking # Assumes use of SAMR21 board # name of your application @@ -45,14 +45,13 @@ CFLAGS += -DSLIP_BAUDRATE=$(SLIP_BAUDRATE) USEPKG += nanocoap # Required by nanocoap, but only due to issue #5959. USEMODULE += posix -# Required by nanocoap to compile nanocoap_sock. -USEMODULE += gnrc_sock_udp # Include packages that pull up and auto-init the link layer. # NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present USEMODULE += gnrc_netdev_default USEMODULE += auto_init_gnrc_netif # Specify the mandatory networking modules +USEMODULE += gnrc_sock_udp USEMODULE += gcoap # Add a routing protocol USEMODULE += gnrc_rpl diff --git a/examples/gcoap/README.md b/examples/gcoap/README.md index 46ccdcabb4..a795838534 100644 --- a/examples/gcoap/README.md +++ b/examples/gcoap/README.md @@ -1,6 +1,6 @@ # gcoap Example -This application provides command line access to gcoap, a GNRC implementation of CoAP. See the [CoAP spec][1] for background, and the Modules>Networking>GNRC>CoAP topic in the source documentation for the structure of the implementation. +This application provides command line access to gcoap, a high-level API for CoAP messaging. See the [CoAP spec][1] for background, and the Modules>Networking>CoAP topic in the source documentation for detailed usage instructions and implementation notes. We support two setup options for this example: diff --git a/examples/gcoap/gcoap_cli.c b/examples/gcoap/gcoap_cli.c index 75de7dceee..69e774de71 100644 --- a/examples/gcoap/gcoap_cli.c +++ b/examples/gcoap/gcoap_cli.c @@ -96,22 +96,27 @@ static ssize_t _stats_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len) static size_t _send(uint8_t *buf, size_t len, char *addr_str, char *port_str) { ipv6_addr_t addr; - uint16_t port; size_t bytes_sent; + sock_udp_ep_t remote; + + remote.family = AF_INET6; + remote.netif = SOCK_ADDR_ANY_NETIF; /* parse destination address */ if (ipv6_addr_from_str(&addr, addr_str) == NULL) { puts("gcoap_cli: unable to parse destination address"); return 0; } + memcpy(&remote.addr.ipv6[0], &addr.u8[0], sizeof(addr.u8)); + /* parse port */ - port = (uint16_t)atoi(port_str); - if (port == 0) { + remote.port = (uint16_t)atoi(port_str); + if (remote.port == 0) { puts("gcoap_cli: unable to parse destination port"); return 0; } - bytes_sent = gcoap_req_send(buf, len, &addr, port, _resp_handler); + bytes_sent = gcoap_req_send2(buf, len, &remote, _resp_handler); if (bytes_sent > 0) { req_count++; } From acda73c9c77eec7f4c581a988b64bcc07e5415cd Mon Sep 17 00:00:00 2001 From: Ken Bannister Date: Thu, 17 Nov 2016 00:03:39 -0500 Subject: [PATCH 4/5] gcoap: Update unit tests for rebase on sock --- tests/unittests/tests-gcoap/Makefile.include | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/unittests/tests-gcoap/Makefile.include b/tests/unittests/tests-gcoap/Makefile.include index db3b1c3527..c32f5a9edc 100644 --- a/tests/unittests/tests-gcoap/Makefile.include +++ b/tests/unittests/tests-gcoap/Makefile.include @@ -1,9 +1,8 @@ USEPKG += nanocoap -# Required by nanocoap to compile nanocoap_sock. -USEMODULE += gnrc_sock_udp # Specify the mandatory networking modules USEMODULE += gcoap +USEMODULE += gnrc_sock_udp USEMODULE += gnrc_ipv6 USEMODULE += random From 342c3f2ed313b78cc29b70c1d7b577cea3b77de0 Mon Sep 17 00:00:00 2001 From: Ken Bannister Date: Sun, 15 Jan 2017 06:18:04 -0500 Subject: [PATCH 5/5] gcoap: Remove coap.h include file, which is no longer used. Also change references in dependencies to the net/gcoap.h include. --- examples/gcoap/gcoap_cli.c | 2 +- examples/gcoap/main.c | 2 +- sys/auto_init/auto_init.c | 2 +- sys/include/net/gnrc/coap.h | 23 ----------------------- tests/unittests/tests-gcoap/tests-gcoap.c | 2 +- 5 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 sys/include/net/gnrc/coap.h diff --git a/examples/gcoap/gcoap_cli.c b/examples/gcoap/gcoap_cli.c index 69e774de71..4e03f280e3 100644 --- a/examples/gcoap/gcoap_cli.c +++ b/examples/gcoap/gcoap_cli.c @@ -22,7 +22,7 @@ #include #include #include -#include "net/gnrc/coap.h" +#include "net/gcoap.h" #include "od.h" #include "fmt.h" diff --git a/examples/gcoap/main.c b/examples/gcoap/main.c index 845d800a5a..3757922d0e 100644 --- a/examples/gcoap/main.c +++ b/examples/gcoap/main.c @@ -21,7 +21,7 @@ #include #include "msg.h" -#include "net/gnrc/coap.h" +#include "net/gcoap.h" #include "kernel_types.h" #include "shell.h" diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 5af0e8f005..2a55037535 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -89,7 +89,7 @@ #endif #ifdef MODULE_GCOAP -#include "net/gnrc/coap.h" +#include "net/gcoap.h" #endif #define ENABLE_DEBUG (0) diff --git a/sys/include/net/gnrc/coap.h b/sys/include/net/gnrc/coap.h deleted file mode 100644 index 33022a131f..0000000000 --- a/sys/include/net/gnrc/coap.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2015-2016 Ken Bannister. All rights reserved. - * - * 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 - * directory for more details. - */ - -/** - * @ingroup net_gcoap - * @brief Adapter for migration of GNRC-based gcoap to sock-based gcoap - * @deprecated Use net/gcoap.h instead. - * - * @{ - * - * @file - * - * @author Ken Bannister - */ - -#include "net/gcoap.h" - -/** @} */ diff --git a/tests/unittests/tests-gcoap/tests-gcoap.c b/tests/unittests/tests-gcoap/tests-gcoap.c index c46a368d13..b58d4cb8f1 100644 --- a/tests/unittests/tests-gcoap/tests-gcoap.c +++ b/tests/unittests/tests-gcoap/tests-gcoap.c @@ -17,7 +17,7 @@ #include "embUnit.h" -#include "net/gnrc/coap.h" +#include "net/gcoap.h" #include "unittests-constants.h" #include "tests-gcoap.h"