1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #17843 from benpicco/gcoap-block-server

examples/gcoap_block_server: add gcoap block server example
This commit is contained in:
benpicco 2022-04-03 00:19:43 +02:00 committed by GitHub
commit ac4ac64e58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 306 additions and 0 deletions

View File

@ -0,0 +1,47 @@
# Default Makefile, for host native GNRC-based networking
# name of your application
APPLICATION = gcoap_example
# If no BOARD is found in the environment, use this default:
BOARD ?= native
# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..
## Uncomment to redefine port, for example use 61616 for RFC 6282 UDP compression.
#GCOAP_PORT = 5683
#CFLAGS += -DGCOAP_PORT=$(GCOAP_PORT)
## Uncomment to redefine request token length, max 8.
#GCOAP_TOKENLEN = 2
#CFLAGS += -DGCOAP_TOKENLEN=$(GCOAP_TOKENLEN)
# Include packages that pull up and auto-init the link layer.
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
USEMODULE += netdev_default
USEMODULE += auto_init_gnrc_netif
# Specify the mandatory networking modules
USEMODULE += gnrc_ipv6_default
USEMODULE += gcoap
# Additional networking modules that can be dropped if not needed
USEMODULE += gnrc_icmpv6_echo
#USEMODULE += gnrc_rpl
# Required by handlers
USEMODULE += fmt
USEMODULE += hashes
# Add also the shell, some shell commands
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,38 @@
BOARD_INSUFFICIENT_MEMORY := \
arduino-duemilanove \
arduino-leonardo \
arduino-mega2560 \
arduino-nano \
arduino-uno \
atmega1284p \
atmega328p \
atmega328p-xplained-mini \
atxmega-a3bu-xplained \
bluepill-stm32f030c8 \
derfmega128 \
i-nucleo-lrwan1 \
m1284p \
mega-xplained \
microduino-corerf \
msb-430 \
msb-430h \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f042k6 \
nucleo-f303k8 \
nucleo-f334r8 \
nucleo-l011k4 \
nucleo-l031k6 \
nucleo-l053r8 \
samd10-xmini \
slstk3400a \
stk3200 \
stm32f030f4-demo \
stm32f0discovery \
stm32g0316-disco \
stm32l0538-disco \
telosb \
waspmote-pro \
z1 \
zigduino \
#

View File

@ -0,0 +1,8 @@
This application provides examples of CoAP server handling for Block requests, build with gcoap using nanocoap block handling functions.
This show the current status and is very likely to change with improvements made to gcoap and nanocoap and their API, see example/nanocoap_server for comparison.
Relevant resources:
* `/riot/ver` -- provides Block2 response payloads for GET request
* `/sha256` -- provides SHA-256 digest from Block1 POST request input

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2015-2017 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.
*/
/**
* @{
*
* @file
* @brief gcoap block server handler example
*
* @author Ken Bannister <kb2ma@runbox.com>
*
* @}
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fmt.h"
#include "hashes/sha256.h"
#include "net/gcoap.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static ssize_t _sha256_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx);
static ssize_t _riot_block2_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx);
/* CoAP resources */
static const coap_resource_t _resources[] = {
{ "/riot/ver", COAP_GET, _riot_block2_handler, NULL },
{ "/sha256", COAP_POST, _sha256_handler, NULL },
};
static gcoap_listener_t _listener = {
.resources = _resources,
.resources_len = ARRAY_SIZE(_resources),
};
/* Constants for /riot/ver. */
static const uint8_t block2_intro[] = "This is RIOT (Version: ";
static const uint8_t block2_board[] = " running on a ";
static const uint8_t block2_mcu[] = " board with a ";
static ssize_t _riot_block2_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx)
{
(void)ctx;
coap_block_slicer_t slicer;
coap_block2_init(pdu, &slicer);
gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT);
coap_opt_add_format(pdu, COAP_FORMAT_TEXT);
coap_opt_add_block2(pdu, &slicer, 1);
ssize_t plen = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD);
/* Add actual content */
plen += coap_blockwise_put_bytes(&slicer, buf+plen, block2_intro, sizeof(block2_intro)-1);
plen += coap_blockwise_put_bytes(&slicer, buf+plen, (uint8_t*)RIOT_VERSION, strlen(RIOT_VERSION));
plen += coap_blockwise_put_char(&slicer, buf+plen, ')');
plen += coap_blockwise_put_bytes(&slicer, buf+plen, block2_board, sizeof(block2_board)-1);
plen += coap_blockwise_put_bytes(&slicer, buf+plen, (uint8_t*)RIOT_BOARD, strlen(RIOT_BOARD));
plen += coap_blockwise_put_bytes(&slicer, buf+plen, block2_mcu, sizeof(block2_mcu)-1);
plen += coap_blockwise_put_bytes(&slicer, buf+plen, (uint8_t*)RIOT_MCU, strlen(RIOT_MCU));
/* To demonstrate individual chars */
plen += coap_blockwise_put_char(&slicer, buf+plen, ' ');
plen += coap_blockwise_put_char(&slicer, buf+plen, 'M');
plen += coap_blockwise_put_char(&slicer, buf+plen, 'C');
plen += coap_blockwise_put_char(&slicer, buf+plen, 'U');
plen += coap_blockwise_put_char(&slicer, buf+plen, '.');
coap_block2_finish(&slicer);
return plen;
}
/*
* Uses block1 POSTs to generate an sha256 digest. */
static ssize_t _sha256_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx)
{
(void)ctx;
/* using a shared sha256 context *will* break if two requests are handled
* at the same time. doing it anyways, as this is meant to showcase block1
* support, not proper synchronisation. */
static sha256_context_t sha256;
uint8_t digest[SHA256_DIGEST_LENGTH];
coap_block1_t block1;
int blockwise = coap_get_block1(pdu, &block1);
printf("_sha256_handler: received data: offset=%u len=%u blockwise=%i more=%i\n",
(unsigned)block1.offset, pdu->payload_len, blockwise, block1.more);
/* initialize sha256 calculation and add payload bytes */
if (block1.blknum == 0) {
puts("_sha256_handler: init");
sha256_init(&sha256);
}
sha256_update(&sha256, pdu->payload, pdu->payload_len);
unsigned resp_code = COAP_CODE_CHANGED;
if (block1.more) {
resp_code = COAP_CODE_CONTINUE;
}
/* start response */
gcoap_resp_init(pdu, buf, len, resp_code);
/* has payload */
if (!blockwise || !block1.more) {
coap_opt_add_format(pdu, COAP_FORMAT_TEXT);
}
if (blockwise) {
coap_opt_add_block1_control(pdu, &block1);
}
/* include digest if done, otherwise response code above asks for next block */
size_t pdu_len = 0;
if (!blockwise || !block1.more) {
puts("_sha256_handler: finish");
sha256_final(&sha256, digest);
pdu_len = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD);
pdu_len += fmt_bytes_hex((char *)pdu->payload, digest, sizeof(digest));
}
else {
pdu_len = coap_opt_finish(pdu, COAP_OPT_FINISH_NONE);
}
return pdu_len;
}
int gcoap_cli_cmd(int argc, char **argv)
{
if (argc == 1) {
/* show help for main commands */
goto end;
}
if (strcmp(argv[1], "info") == 0) {
uint8_t open_reqs = gcoap_op_state();
printf("CoAP server is listening on port %u\n", CONFIG_GCOAP_PORT);
printf("CoAP open requests: %u\n", open_reqs);
return 0;
}
end:
printf("usage: %s <info>\n", argv[0]);
return 1;
}
void gcoap_cli_init(void)
{
gcoap_register_listener(&_listener);
}

View File

@ -0,0 +1,52 @@
/*
* 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 examples
* @{
*
* @file
* @brief gcoap example
*
* @author Ken Bannister <kb2ma@runbox.com>
*
* @}
*/
#include <stdio.h>
#include "msg.h"
#include "net/gcoap.h"
#include "shell.h"
#define MAIN_QUEUE_SIZE (4)
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
extern int gcoap_cli_cmd(int argc, char **argv);
extern void gcoap_cli_init(void);
static const shell_command_t shell_commands[] = {
{ "coap", "CoAP example", gcoap_cli_cmd },
{ NULL, NULL, NULL }
};
int main(void)
{
/* for the thread running the shell */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
gcoap_cli_init();
puts("gcoap block handler");
/* start shell */
puts("All up, running the shell now");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
/* should never be reached */
return 0;
}