Skip to content

Commit

Permalink
Merge pull request #17937 from benpicco/nanocoap_vfs
Browse files Browse the repository at this point in the history
nanocoap_vfs: add nanocoap_vfs_get()
  • Loading branch information
benpicco authored May 24, 2022
2 parents a61c4b7 + 5fde41e commit 85169fc
Show file tree
Hide file tree
Showing 10 changed files with 334 additions and 2 deletions.
2 changes: 1 addition & 1 deletion examples/suit_update/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ include $(RIOTBASE)/Makefile.include
# allow to use large blocks to utilize large MTUs (802.15.4g, Ethernet, WiFi)
LARGE_BLOCKS ?= 0
ifeq (1, $(LARGE_BLOCKS))
CFLAGS += -DCONFIG_SUIT_COAP_BLOCKSIZE=COAP_BLOCKSIZE_1024
CFLAGS += -DCONFIG_NANOCOAP_BLOCKSIZE_DEFAULT=COAP_BLOCKSIZE_1024
else
# lower pktbuf size to something sufficient for this application
# Set GNRC_PKTBUF_SIZE via CFLAGS if not being set via Kconfig.
Expand Down
5 changes: 5 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,11 @@ ifneq (,$(filter nanocoap_cache,$(USEMODULE)))
USEMODULE += hashes
endif

ifneq (,$(filter nanocoap_vfs,$(USEMODULE)))
USEMODULE += nanocoap_sock
USEMODULE += vfs
endif

ifneq (,$(filter nanocoap_%,$(USEMODULE)))
USEMODULE += nanocoap
endif
Expand Down
7 changes: 7 additions & 0 deletions sys/include/net/nanocoap.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,13 @@ extern "C" {
#define CONFIG_NANOCOAP_BLOCK_SIZE_EXP_MAX (6)
#endif

/**
* @brief CoAP block-wise-transfer size that should be used by default
*/
#ifndef CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT
#define CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT COAP_BLOCKSIZE_64
#endif

/** @brief Maximum length of a query string written to a message */
#ifndef CONFIG_NANOCOAP_QS_MAX
#define CONFIG_NANOCOAP_QS_MAX (64)
Expand Down
58 changes: 58 additions & 0 deletions sys/include/net/nanocoap_vfs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2022 ML!PA Consulting GmbH
*
* 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_nanosock
* @brief VFS NanoCoAP helper functions
*
* @{
*
* @file
* @brief VFS NanoCoAP helper functions
*
* @author Benjamin Valentin <[email protected]>
*/
#ifndef NET_NANOCOAP_VFS_H
#define NET_NANOCOAP_VFS_H

#include "net/nanocoap_sock.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Downloads the resource behind @p url via blockwise
* GET and stores it in the file @p dst.
*
* @param[in] url URL to the resource
* @param[in] dst Path to the destination file
*
* @returns 0 on success
* @returns <0 on error
*/
int nanocoap_vfs_get_url(const char *url, const char *dst);

/**
* @brief Downloads the resource behind @p path via blockwise
* GET and stores it in the file @p dst.
*
* @param[in] sock Connection to the server
* @param[in] path Remote query path to the resource
* @param[in] dst Local path to the destination file
*
* @returns 0 on success
* @returns <0 on error
*/
int nanocoap_vfs_get(nanocoap_sock_t *sock, const char *path, const char *dst);

#ifdef __cplusplus
}
#endif
#endif /* NET_NANOCOAP_VFS_H */
/** @} */
2 changes: 1 addition & 1 deletion sys/include/suit/transport/coap.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ extern const coap_resource_subtree_t coap_resource_subtree_suit;
* @brief Coap block-wise-transfer size used for SUIT
*/
#ifndef CONFIG_SUIT_COAP_BLOCKSIZE
#define CONFIG_SUIT_COAP_BLOCKSIZE COAP_BLOCKSIZE_64
#define CONFIG_SUIT_COAP_BLOCKSIZE CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT
#endif

/**
Expand Down
94 changes: 94 additions & 0 deletions sys/net/application_layer/nanocoap/vfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2022 ML!PA Consulting GmbH
*
* 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_nanocoap
* @{
*
* @file
* @brief Nanocoap VFS helpers
*
* @author Benjamin Valentin <[email protected]>
*
* @}
*/

#include <fcntl.h>
#include "net/nanocoap_sock.h"
#include "net/sock/util.h"
#include "vfs.h"

#define ENABLE_DEBUG 0
#include "debug.h"

static int _2file(void *arg, size_t offset, uint8_t *buf, size_t len, int more)
{
(void)more;
int *fd = arg;

vfs_lseek(*fd, offset, SEEK_SET);
return vfs_write(*fd, buf, len);
}

static int _prepare_file(const char *dst, char *dst_tmp, size_t len)
{
/* download to temp file, rename it later */
if (snprintf(dst_tmp, len, "%s.t", dst) > (int)len) {
return -ENOBUFS;
}

return vfs_open(dst_tmp, O_CREAT | O_WRONLY | O_TRUNC, 0644);
}

static int _finalize_file(int fd, int res, const char *dst, const char *dst_tmp)
{
vfs_close(fd);

/* move file to it's final location */
if (res >= 0) {
DEBUG("nanocoap: moving %s to %s\n", dst_tmp, dst);
vfs_unlink(dst);
res = vfs_rename(dst_tmp, dst);
}

vfs_unlink(dst_tmp);

return res;
}

int nanocoap_vfs_get(nanocoap_sock_t *sock, const char *path, const char *dst)
{
int fd, res;
char dst_tmp[CONFIG_SOCK_URLPATH_MAXLEN];

DEBUG("nanocoap: downloading %s to %s\n", path, dst_tmp);

fd = _prepare_file(dst, dst_tmp, sizeof(dst_tmp));
if (fd < 0) {
return fd;
}
res = nanocoap_sock_get_blockwise(sock, path, CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT,
_2file, &fd);
return _finalize_file(fd, res, dst, dst_tmp);
}

int nanocoap_vfs_get_url(const char *url, const char *dst)
{
int fd, res;
char dst_tmp[CONFIG_SOCK_URLPATH_MAXLEN];

DEBUG("nanocoap: downloading %s to %s\n", url, dst_tmp);

fd = _prepare_file(dst, dst_tmp, sizeof(dst_tmp));
if (fd < 0) {
return fd;
}
res = nanocoap_get_blockwise_url(url, CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT,
_2file, &fd);
return _finalize_file(fd, res, dst, dst_tmp);
}
4 changes: 4 additions & 0 deletions sys/shell/commands/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ ifneq (,$(filter semtech-loramac,$(USEPKG)))
SRC += sc_loramac.c
endif

ifneq (,$(filter nanocoap_vfs,$(USEMODULE)))
SRC += sc_nanocoap_vfs.c
endif

ifneq (,$(filter nimble_netif,$(USEMODULE)))
SRC += sc_nimble_netif.c
endif
Expand Down
139 changes: 139 additions & 0 deletions sys/shell/commands/sc_nanocoap_vfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright (C) 2022 ML!PA Consulting GmbH
*
* 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 sys_shell_commands
* @{
*
* @file
* @brief NanoCoAP commands that interact with the filesystem
*
* @author Benjamin Valentin <[email protected]>
*
* @}
*/

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

#include "vfs_default.h"
#include "net/nanocoap_vfs.h"
#include "net/nanocoap_sock.h"

struct dir_list_ctx {
char *buf;
char *cur;
char *end;
};

static bool _is_dir(const char *url)
{
int len = strlen(url);
return url[len - 1] == '/';
}

static int _print_cb(void *arg, size_t offset, uint8_t *buf, size_t len, int more)
{
(void)arg;
(void)offset;

write(STDOUT_FILENO, buf, len);
if (!more) {
puts("");
}

return 0;
}

static int _print_dir_cb(void *arg, size_t offset, uint8_t *buf, size_t len, int more)
{
(void)offset;
(void)more;

struct dir_list_ctx *ctx = arg;

char *end = (char *)buf + len;
for (char *c = (char *)buf; c < end; ++c) {
if (ctx->cur) {
if (*c == '>' || ctx->cur == ctx->end) {
*ctx->cur = 0;
puts(ctx->buf);
ctx->cur = NULL;
} else {
*ctx->cur++ = *c;
}
} else if (*c == '<') {
ctx->cur = ctx->buf;
}
}

return 0;
}

static int _print_dir(const char *url, char *buf, size_t len)
{
struct dir_list_ctx ctx = {
.buf = buf,
.end = buf + len,
};
return nanocoap_get_blockwise_url(url, CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT,
_print_dir_cb, &ctx);
}

int _nanocoap_get_handler(int argc, char **argv)
{
int res;
char buffer[CONFIG_NANOCOAP_QS_MAX];
char *dst, *url = argv[1];

if (argc < 2) {
printf("Usage: %s <url> [destination]\n", argv[0]);
printf("Default destination: %s\n", VFS_DEFAULT_DATA);
return -EINVAL;
}

if (_is_dir(url) && argc < 3) {
res = _print_dir(url, buffer, sizeof(buffer));
if (res) {
printf("Request failed: %s\n", strerror(-res));
}
return res;
}

if (argc < 3) {
dst = strrchr(url, '/');
if (dst == NULL) {
printf("invalid url: '%s'\n", url);
return -EINVAL;
}
if (snprintf(buffer, sizeof(buffer), "%s%s",
VFS_DEFAULT_DATA, dst) >= (int)sizeof(buffer)) {
printf("Output file path too long\n");
return -ENOBUFS;
}
dst = buffer;
} else {
dst = argv[2];
}

/* alternatively write the file to stdout */
if (strcmp(dst, "-") == 0) {
return nanocoap_get_blockwise_url(url, CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT,
_print_cb, NULL);
}

res = nanocoap_vfs_get_url(url, dst);
if (res < 0) {
printf("Download failed: %s\n", strerror(-res));
} else {
printf("Saved as %s\n", dst);
}
return res;
}
7 changes: 7 additions & 0 deletions sys/shell/commands/shell_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ extern int _i2c_scan(int argc, char **argv);
extern int _loramac_handler(int argc, char **argv);
#endif

#ifdef MODULE_NANOCOAP_VFS
extern int _nanocoap_get_handler(int argc, char **argv);
#endif

#ifdef MODULE_NICE
extern int _sc_nice(int argc, char **argv);
#endif
Expand Down Expand Up @@ -289,6 +293,9 @@ const shell_command_t _shell_command_list[] = {
#ifdef MODULE_SHA256SUM
{"sha256sum", "Compute and check SHA256 message digest", _vfs_sha256sum_cmd},
#endif
#ifdef MODULE_NANOCOAP_VFS
{"ncget", "download a file from a CoAP server", _nanocoap_get_handler},
#endif
#ifdef MODULE_GNRC_IPV6_NIB
{"nib", "Configure neighbor information base", _gnrc_ipv6_nib},
#endif
Expand Down
18 changes: 18 additions & 0 deletions tests/nanocoap_cli/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@ USEMODULE += gnrc_ipv6_default

USEMODULE += nanocoap_sock

# boards where basic nanocoap functionality fits, but no VFS
LOW_MEMORY_BOARDS := atmega1284p atxmega-a3bu-xplained derfmega128 \
saml11-xpro bluepill saml10-xpro blackpill nucleo-f302r8 \
stm32mp157c-dk2 stm32f7508-dk

# Don't enable VFS functions on small boards
ifeq (,$(filter $(BOARD),$(LOW_MEMORY_BOARDS)))
USEMODULE += nanocoap_vfs
USEMODULE += vfs_default
# USEMODULE += vfs_auto_format
USEMODULE += shell_commands

# always enable auto-format for native
ifeq ($(BOARD),native)
USEMODULE += vfs_auto_format
endif
endif

# Required by test
USEMODULE += od
USEMODULE += shell
Expand Down

0 comments on commit 85169fc

Please sign in to comment.