Merge pull request #6117 from kb2ma/gcoap/sock
gcoap: rebase networking on sock
This commit is contained in:
commit
85d8397464
@ -96,10 +96,6 @@ ifneq (,$(filter gnrc_zep,$(USEMODULE)))
|
|||||||
USEMODULE += xtimer
|
USEMODULE += xtimer
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter gcoap,$(USEMODULE)))
|
|
||||||
USEMODULE += gnrc_udp
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq (,$(filter gnrc_tftp,$(USEMODULE)))
|
ifneq (,$(filter gnrc_tftp,$(USEMODULE)))
|
||||||
USEMODULE += gnrc_udp
|
USEMODULE += gnrc_udp
|
||||||
USEMODULE += xtimer
|
USEMODULE += xtimer
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Default Makefile, for host native networking
|
# Default Makefile, for host native GNRC-based networking
|
||||||
|
|
||||||
# name of your application
|
# name of your application
|
||||||
APPLICATION = gcoap
|
APPLICATION = gcoap
|
||||||
@ -29,8 +29,6 @@ BOARD_BLACKLIST := nrf52dk
|
|||||||
USEPKG += nanocoap
|
USEPKG += nanocoap
|
||||||
# Required by nanocoap, but only due to issue #5959.
|
# Required by nanocoap, but only due to issue #5959.
|
||||||
USEMODULE += posix
|
USEMODULE += posix
|
||||||
# Required by nanocoap to compile nanocoap_sock.
|
|
||||||
USEMODULE += gnrc_sock_udp
|
|
||||||
|
|
||||||
# Include packages that pull up and auto-init the link layer.
|
# Include packages that pull up and auto-init the link layer.
|
||||||
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
|
# 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
|
USEMODULE += auto_init_gnrc_netif
|
||||||
# Specify the mandatory networking modules
|
# Specify the mandatory networking modules
|
||||||
USEMODULE += gnrc_ipv6_default
|
USEMODULE += gnrc_ipv6_default
|
||||||
|
USEMODULE += gnrc_sock_udp
|
||||||
USEMODULE += gcoap
|
USEMODULE += gcoap
|
||||||
# Additional networking modules that can be dropped if not needed
|
# Additional networking modules that can be dropped if not needed
|
||||||
USEMODULE += gnrc_icmpv6_echo
|
USEMODULE += gnrc_icmpv6_echo
|
||||||
|
|||||||
@ -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
|
# Assumes use of SAMR21 board
|
||||||
|
|
||||||
# name of your application
|
# name of your application
|
||||||
@ -45,14 +45,13 @@ CFLAGS += -DSLIP_BAUDRATE=$(SLIP_BAUDRATE)
|
|||||||
USEPKG += nanocoap
|
USEPKG += nanocoap
|
||||||
# Required by nanocoap, but only due to issue #5959.
|
# Required by nanocoap, but only due to issue #5959.
|
||||||
USEMODULE += posix
|
USEMODULE += posix
|
||||||
# Required by nanocoap to compile nanocoap_sock.
|
|
||||||
USEMODULE += gnrc_sock_udp
|
|
||||||
|
|
||||||
# Include packages that pull up and auto-init the link layer.
|
# Include packages that pull up and auto-init the link layer.
|
||||||
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
|
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
|
||||||
USEMODULE += gnrc_netdev_default
|
USEMODULE += gnrc_netdev_default
|
||||||
USEMODULE += auto_init_gnrc_netif
|
USEMODULE += auto_init_gnrc_netif
|
||||||
# Specify the mandatory networking modules
|
# Specify the mandatory networking modules
|
||||||
|
USEMODULE += gnrc_sock_udp
|
||||||
USEMODULE += gcoap
|
USEMODULE += gcoap
|
||||||
# Add a routing protocol
|
# Add a routing protocol
|
||||||
USEMODULE += gnrc_rpl
|
USEMODULE += gnrc_rpl
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# gcoap Example
|
# 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:
|
We support two setup options for this example:
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "net/gnrc/coap.h"
|
#include "net/gcoap.h"
|
||||||
#include "od.h"
|
#include "od.h"
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
|
|
||||||
@ -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)
|
static size_t _send(uint8_t *buf, size_t len, char *addr_str, char *port_str)
|
||||||
{
|
{
|
||||||
ipv6_addr_t addr;
|
ipv6_addr_t addr;
|
||||||
uint16_t port;
|
|
||||||
size_t bytes_sent;
|
size_t bytes_sent;
|
||||||
|
sock_udp_ep_t remote;
|
||||||
|
|
||||||
|
remote.family = AF_INET6;
|
||||||
|
remote.netif = SOCK_ADDR_ANY_NETIF;
|
||||||
|
|
||||||
/* parse destination address */
|
/* parse destination address */
|
||||||
if (ipv6_addr_from_str(&addr, addr_str) == NULL) {
|
if (ipv6_addr_from_str(&addr, addr_str) == NULL) {
|
||||||
puts("gcoap_cli: unable to parse destination address");
|
puts("gcoap_cli: unable to parse destination address");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
memcpy(&remote.addr.ipv6[0], &addr.u8[0], sizeof(addr.u8));
|
||||||
|
|
||||||
/* parse port */
|
/* parse port */
|
||||||
port = (uint16_t)atoi(port_str);
|
remote.port = (uint16_t)atoi(port_str);
|
||||||
if (port == 0) {
|
if (remote.port == 0) {
|
||||||
puts("gcoap_cli: unable to parse destination port");
|
puts("gcoap_cli: unable to parse destination port");
|
||||||
return 0;
|
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) {
|
if (bytes_sent > 0) {
|
||||||
req_count++;
|
req_count++;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "msg.h"
|
#include "msg.h"
|
||||||
|
|
||||||
#include "net/gnrc/coap.h"
|
#include "net/gcoap.h"
|
||||||
#include "kernel_types.h"
|
#include "kernel_types.h"
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
|
|
||||||
|
|||||||
@ -99,6 +99,9 @@ endif
|
|||||||
ifneq (,$(filter sema,$(USEMODULE)))
|
ifneq (,$(filter sema,$(USEMODULE)))
|
||||||
DIRS += sema
|
DIRS += sema
|
||||||
endif
|
endif
|
||||||
|
ifneq (,$(filter gcoap,$(USEMODULE)))
|
||||||
|
DIRS += net/application_layer/coap
|
||||||
|
endif
|
||||||
|
|
||||||
DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))
|
DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))
|
||||||
|
|
||||||
|
|||||||
@ -89,7 +89,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODULE_GCOAP
|
#ifdef MODULE_GCOAP
|
||||||
#include "net/gnrc/coap.h"
|
#include "net/gcoap.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ENABLE_DEBUG (0)
|
#define ENABLE_DEBUG (0)
|
||||||
|
|||||||
@ -7,16 +7,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup net_gnrc_coap CoAP
|
* @defgroup net_gcoap CoAP
|
||||||
* @ingroup net_gnrc
|
* @ingroup net
|
||||||
* @brief GNRC implementation of CoAP protocol, RFC 7252
|
* @brief High-level interface to CoAP messaging
|
||||||
*
|
*
|
||||||
* ## Architecture ##
|
* gcoap provides a high-level interface for writing CoAP messages via RIOT's
|
||||||
* Requests and responses are exchanged via an asynchronous RIOT message
|
* sock networking API. gcoap internalizes network event processing so an
|
||||||
* processing thread. Depends on nanocoap for base level structs and
|
* application only needs to focus on request/response handling. For a server,
|
||||||
* functionality.
|
* 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 ##
|
* ## Server Operation ##
|
||||||
*
|
*
|
||||||
@ -61,11 +68,10 @@
|
|||||||
*
|
*
|
||||||
* ## Client Operation ##
|
* ## Client Operation ##
|
||||||
*
|
*
|
||||||
* gcoap uses RIOT's asynchronous messaging facility to send and receive
|
* Client operation includes two phases: creating and sending a request, and
|
||||||
* messages. So, client operation includes two phases: creating and sending a
|
* handling the response aynchronously in a client supplied callback. See
|
||||||
* request, and handling the response aynchronously in a client supplied
|
* `examples/gcoap/gcoap_cli.c` for a simple example of sending a request and
|
||||||
* callback. See `examples/gcoap/gcoap_cli.c` for a simple example of sending
|
* reading the response.
|
||||||
* a request and reading the response.
|
|
||||||
*
|
*
|
||||||
* ### Creating a request ###
|
* ### Creating a request ###
|
||||||
*
|
*
|
||||||
@ -85,8 +91,8 @@
|
|||||||
* as described above. The gcoap_request() function is inline, and uses those
|
* as described above. The gcoap_request() function is inline, and uses those
|
||||||
* two functions.
|
* two functions.
|
||||||
*
|
*
|
||||||
* Finally, call gcoap_req_send() with the destination host and port, as well
|
* Finally, call gcoap_req_send2() for the destination endpoint, as well as a
|
||||||
* as a callback function for the host's response.
|
* callback function for the host's response.
|
||||||
*
|
*
|
||||||
* ### Handling the response ###
|
* ### Handling the response ###
|
||||||
*
|
*
|
||||||
@ -114,13 +120,13 @@
|
|||||||
* header and the payload. So, gcoap provides space in the buffer for them in
|
* header and the payload. So, gcoap provides space in the buffer for them in
|
||||||
* the request/response ...init() function, and then writes them during
|
* the request/response ...init() function, and then writes them during
|
||||||
* gcoap_finish(). We trade some inefficiency/work in the buffer for
|
* gcoap_finish(). We trade some inefficiency/work in the buffer for
|
||||||
* simplicity for the user.
|
* simplicity in the API.
|
||||||
*
|
*
|
||||||
* ### Waiting for a response ###
|
* ### Waiting for a response ###
|
||||||
*
|
*
|
||||||
* We take advantage of RIOT's GNRC stack by using an xtimer to wait for a
|
* We take advantage of RIOT's asynchronous messaging by using an xtimer to wait
|
||||||
* response, so the gcoap thread does not block while waiting. The user is
|
* 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
|
* notified via the same callback, whether the message is received or the wait
|
||||||
* times out. We track the response with an entry in the
|
* times out. We track the response with an entry in the
|
||||||
* `_coap_state.open_reqs` array.
|
* `_coap_state.open_reqs` array.
|
||||||
*
|
*
|
||||||
@ -135,9 +141,7 @@
|
|||||||
#ifndef GCOAP_H
|
#ifndef GCOAP_H
|
||||||
#define GCOAP_H
|
#define GCOAP_H
|
||||||
|
|
||||||
#include "net/gnrc.h"
|
#include "net/sock/udp.h"
|
||||||
#include "net/gnrc/ipv6.h"
|
|
||||||
#include "net/gnrc/udp.h"
|
|
||||||
#include "nanocoap.h"
|
#include "nanocoap.h"
|
||||||
#include "xtimer.h"
|
#include "xtimer.h"
|
||||||
|
|
||||||
@ -199,15 +203,27 @@ extern "C" {
|
|||||||
#define GCOAP_MEMO_ERR (4) /**< Error processing response packet */
|
#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
|
* @brief Default time to wait for a non-confirmable response, in usec
|
||||||
*
|
*
|
||||||
* Set to 0 to disable timeout.
|
* Set to 0 to disable timeout.
|
||||||
*/
|
*/
|
||||||
#define GCOAP_NON_TIMEOUT (5000000U)
|
#define GCOAP_NON_TIMEOUT (5000000U)
|
||||||
|
|
||||||
/** @brief Identifies a gcoap-specific timeout IPC message */
|
/** @brief Identifies waiting timed out for a response to a sent message. */
|
||||||
#define GCOAP_NETAPI_MSG_TYPE_TIMEOUT (0x1501)
|
#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
|
* @brief A modular collection of resources for a server
|
||||||
@ -243,7 +259,6 @@ typedef struct {
|
|||||||
* @brief Container for the state of gcoap itself
|
* @brief Container for the state of gcoap itself
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gnrc_netreg_entry_t netreg_port; /**< Registration for IP port */
|
|
||||||
gcoap_listener_t *listeners; /**< List of registered listeners */
|
gcoap_listener_t *listeners; /**< List of registered listeners */
|
||||||
gcoap_request_memo_t open_reqs[GCOAP_REQ_WAITING_MAX];
|
gcoap_request_memo_t open_reqs[GCOAP_REQ_WAITING_MAX];
|
||||||
/**< Storage for open requests; if first
|
/**< 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;
|
: -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.
|
* @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] buf Buffer containing the PDU
|
||||||
* @param[in] len Length of the buffer
|
* @param[in] len Length of the buffer
|
||||||
* @param[in] addr Destination for the packet
|
* @param[in] addr Destination for the packet
|
||||||
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup net_gnrc_coap
|
* @ingroup net_gcoap
|
||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file
|
* @file
|
||||||
@ -19,7 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "net/gnrc/coap.h"
|
#include "net/gcoap.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
@ -31,14 +31,11 @@
|
|||||||
|
|
||||||
/* Internal functions */
|
/* Internal functions */
|
||||||
static void *_event_loop(void *arg);
|
static void *_event_loop(void *arg);
|
||||||
static int _register_port(gnrc_netreg_entry_t *netreg_port, uint16_t port);
|
static void _listen(sock_udp_t *sock);
|
||||||
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 ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len);
|
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 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 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 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 _expire_request(gcoap_request_memo_t *memo);
|
||||||
static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu,
|
static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu,
|
||||||
uint8_t *buf, size_t len);
|
uint8_t *buf, size_t len);
|
||||||
@ -55,97 +52,91 @@ static gcoap_listener_t _default_listener = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static gcoap_state_t _coap_state = {
|
static gcoap_state_t _coap_state = {
|
||||||
.netreg_port = GNRC_NETREG_ENTRY_INIT_PID(0, KERNEL_PID_UNDEF),
|
|
||||||
.listeners = &_default_listener,
|
.listeners = &_default_listener,
|
||||||
};
|
};
|
||||||
|
|
||||||
static kernel_pid_t _pid = KERNEL_PID_UNDEF;
|
static kernel_pid_t _pid = KERNEL_PID_UNDEF;
|
||||||
static char _msg_stack[GCOAP_STACK_SIZE];
|
static char _msg_stack[GCOAP_STACK_SIZE];
|
||||||
|
static sock_udp_t _sock;
|
||||||
|
|
||||||
|
|
||||||
/* Event/Message loop for gcoap _pid thread. */
|
/* Event/Message loop for gcoap _pid thread. */
|
||||||
static void *_event_loop(void *arg)
|
static void *_event_loop(void *arg)
|
||||||
{
|
{
|
||||||
msg_t msg_rcvd, msg_queue[GCOAP_MSG_QUEUE_SIZE];
|
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;
|
(void)arg;
|
||||||
|
|
||||||
msg_init_queue(msg_queue, GCOAP_MSG_QUEUE_SIZE);
|
msg_init_queue(msg_queue, GCOAP_MSG_QUEUE_SIZE);
|
||||||
|
|
||||||
while (1) {
|
sock_udp_ep_t local;
|
||||||
msg_receive(&msg_rcvd);
|
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) {
|
int res = sock_udp_create(&_sock, &local, NULL, 0);
|
||||||
case GNRC_NETAPI_MSG_TYPE_RCV:
|
if (res < 0) {
|
||||||
/* find client from UDP destination port */
|
DEBUG("gcoap: cannot create sock: %d\n", res);
|
||||||
DEBUG("coap: GNRC_NETAPI_MSG_TYPE_RCV\n");
|
return 0;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handles incoming network IPC message. */
|
/* Listen for an incoming CoAP message. */
|
||||||
static void _receive(gnrc_pktsnip_t *pkt, ipv6_addr_t *src, uint16_t port)
|
static void _listen(sock_udp_t *sock)
|
||||||
{
|
{
|
||||||
coap_pkt_t pdu;
|
coap_pkt_t pdu;
|
||||||
uint8_t buf[GCOAP_PDU_BUF_SIZE];
|
uint8_t buf[GCOAP_PDU_BUF_SIZE];
|
||||||
size_t pdu_len = 0;
|
sock_udp_ep_t remote;
|
||||||
gcoap_request_memo_t *memo = NULL;
|
gcoap_request_memo_t *memo = NULL;
|
||||||
|
uint8_t open_reqs;
|
||||||
|
|
||||||
/* If too big, handle below based on request vs. response */
|
gcoap_op_state(&open_reqs);
|
||||||
size_t pkt_size = (pkt->size > sizeof(buf))
|
|
||||||
? sizeof(buf) : pkt->size;
|
|
||||||
|
|
||||||
/* Copy request into temporary buffer, and parse it as CoAP. */
|
ssize_t res = sock_udp_recv(sock, buf, sizeof(buf),
|
||||||
memcpy(buf, pkt->data, pkt_size);
|
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);
|
res = coap_parse(&pdu, buf, res);
|
||||||
if (result < 0) {
|
if (res < 0) {
|
||||||
DEBUG("gcoap: parse failure: %d\n", result);
|
DEBUG("gcoap: parse failure: %d\n", res);
|
||||||
/* If a response, can't clear memo, but it will timeout later. */
|
/* If a response, can't clear memo, but it will timeout later. */
|
||||||
goto exit;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* incoming request */
|
/* incoming request */
|
||||||
if (coap_get_code_class(&pdu) == COAP_CLASS_REQ) {
|
if (coap_get_code_class(&pdu) == COAP_CLASS_REQ) {
|
||||||
if (pkt->size > sizeof(buf)) {
|
size_t pdu_len = _handle_req(&pdu, buf, 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));
|
|
||||||
}
|
|
||||||
if (pdu_len > 0) {
|
if (pdu_len > 0) {
|
||||||
_send_buf(buf, pdu_len, src, port);
|
sock_udp_send(sock, buf, pdu_len, &remote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* incoming response */
|
/* 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));
|
_find_req_memo(&memo, &pdu, buf, sizeof(buf));
|
||||||
if (memo) {
|
if (memo) {
|
||||||
xtimer_remove(&memo->response_timer);
|
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->resp_handler(memo->state, &pdu);
|
||||||
memo->state = GCOAP_MEMO_UNUSED;
|
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
|
* Handler for /.well-known/core. Lists registered handlers, except for
|
||||||
* /.well-known/core itself.
|
* /.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,
|
_pid = thread_create(_msg_stack, sizeof(_msg_stack), THREAD_PRIORITY_MAIN - 1,
|
||||||
THREAD_CREATE_STACKTEST, _event_loop, NULL, "coap");
|
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. */
|
/* 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));
|
memset(&_coap_state.open_reqs[0], 0, sizeof(_coap_state.open_reqs));
|
||||||
/* randomize initial value */
|
/* 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,
|
size_t gcoap_req_send(uint8_t *buf, size_t len, ipv6_addr_t *addr, uint16_t port,
|
||||||
gcoap_resp_handler_t resp_handler)
|
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;
|
gcoap_request_memo_t *memo = NULL;
|
||||||
|
assert(remote != NULL);
|
||||||
assert(resp_handler != NULL);
|
assert(resp_handler != NULL);
|
||||||
|
|
||||||
/* Find empty slot in list of open requests. */
|
/* 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);
|
memcpy(&memo->hdr_buf[0], buf, GCOAP_HEADER_MAXLEN);
|
||||||
memo->resp_handler = resp_handler;
|
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)) {
|
if (res && (GCOAP_NON_TIMEOUT > 0)) {
|
||||||
/* start response wait timer */
|
/* interrupt sock listening (to set a listen timeout) */
|
||||||
memo->timeout_msg.type = GCOAP_NETAPI_MSG_TYPE_TIMEOUT;
|
msg_t mbox_msg;
|
||||||
memo->timeout_msg.content.ptr = (char *)memo;
|
mbox_msg.type = GCOAP_MSG_TYPE_INTR;
|
||||||
xtimer_set_msg(&memo->response_timer, GCOAP_NON_TIMEOUT,
|
mbox_msg.content.value = 0;
|
||||||
&memo->timeout_msg, _pid);
|
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) {
|
else if (!res) {
|
||||||
memo->state = GCOAP_MEMO_UNUSED;
|
memo->state = GCOAP_MEMO_UNUSED;
|
||||||
|
DEBUG("gcoap: sock send failed: %d\n", res);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
@ -136,8 +136,5 @@ endif
|
|||||||
ifneq (,$(filter gnrc_tftp,$(USEMODULE)))
|
ifneq (,$(filter gnrc_tftp,$(USEMODULE)))
|
||||||
DIRS += application_layer/tftp
|
DIRS += application_layer/tftp
|
||||||
endif
|
endif
|
||||||
ifneq (,$(filter gcoap,$(USEMODULE)))
|
|
||||||
DIRS += application_layer/coap
|
|
||||||
endif
|
|
||||||
|
|
||||||
include $(RIOTBASE)/Makefile.base
|
include $(RIOTBASE)/Makefile.base
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
USEPKG += nanocoap
|
USEPKG += nanocoap
|
||||||
# Required by nanocoap to compile nanocoap_sock.
|
|
||||||
USEMODULE += gnrc_sock_udp
|
|
||||||
|
|
||||||
# Specify the mandatory networking modules
|
# Specify the mandatory networking modules
|
||||||
USEMODULE += gcoap
|
USEMODULE += gcoap
|
||||||
|
USEMODULE += gnrc_sock_udp
|
||||||
USEMODULE += gnrc_ipv6
|
USEMODULE += gnrc_ipv6
|
||||||
|
|
||||||
USEMODULE += random
|
USEMODULE += random
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "embUnit.h"
|
#include "embUnit.h"
|
||||||
|
|
||||||
#include "net/gnrc/coap.h"
|
#include "net/gcoap.h"
|
||||||
|
|
||||||
#include "unittests-constants.h"
|
#include "unittests-constants.h"
|
||||||
#include "tests-gcoap.h"
|
#include "tests-gcoap.h"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user