mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #20687 from benpicco/nanocoap_fs
nanocoap_fs: add nanoCoAP as VFS backend (remote CoAP fs)
This commit is contained in:
commit
251ea7f75a
@ -17,14 +17,13 @@
|
|||||||
* @]
|
* @]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "macros/utils.h"
|
||||||
#include "mtd.h"
|
#include "mtd.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <fal.h>
|
#include <fal.h>
|
||||||
|
|
||||||
#define MIN(a, b) ((a) > (b) ? (b) : (a))
|
|
||||||
|
|
||||||
static mtd_dev_t *_mtd;
|
static mtd_dev_t *_mtd;
|
||||||
|
|
||||||
static int _read(long offset, uint8_t *buf, size_t size)
|
static int _read(long offset, uint8_t *buf, size_t size)
|
||||||
|
@ -550,6 +550,12 @@ ifneq (,$(filter nanocoap_cache,$(USEMODULE)))
|
|||||||
USEMODULE += hashes
|
USEMODULE += hashes
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter nanocoap_fs,$(USEMODULE)))
|
||||||
|
USEMODULE += nanocoap_sock
|
||||||
|
USEMODULE += nanocoap_link_format
|
||||||
|
USEMODULE += vfs
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter nanocoap_link_format,$(USEMODULE)))
|
ifneq (,$(filter nanocoap_link_format,$(USEMODULE)))
|
||||||
USEMODULE += fmt
|
USEMODULE += fmt
|
||||||
endif
|
endif
|
||||||
|
67
sys/include/net/nanocoap/fs.h
Normal file
67
sys/include/net/nanocoap/fs.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 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 nanoCoAP virtual file system
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||||
|
*/
|
||||||
|
#ifndef NET_NANOCOAP_FS_H
|
||||||
|
#define NET_NANOCOAP_FS_H
|
||||||
|
|
||||||
|
#include "mutex.h"
|
||||||
|
#include "net/nanocoap_sock.h"
|
||||||
|
#include "vfs.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief nanoCoAP file system configuration
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
const char *url; /**< base URL of the remote fs */
|
||||||
|
nanocoap_sock_t sock; /**< connection to the remote server */
|
||||||
|
mutex_t lock; /**< lock for common urlbuf */
|
||||||
|
char urlbuf[CONFIG_SOCK_URLPATH_MAXLEN]; /**< shared url buffer */
|
||||||
|
} nanocoap_fs_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief nanoCoAP remote file struct
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t offset; /**< offset into the file */
|
||||||
|
char urlbuf[CONFIG_SOCK_URLPATH_MAXLEN]; /**< full path to the file */
|
||||||
|
} nanocoap_fs_file_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief nanoCoAP remote dir struct
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t offset; /**< current directory element */
|
||||||
|
char urlbuf[CONFIG_SOCK_URLPATH_MAXLEN]; /**< full path of the directory */
|
||||||
|
} nanocoap_fs_dir_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief nanoCoAP file system driver
|
||||||
|
*
|
||||||
|
* For use with vfs_mount
|
||||||
|
*/
|
||||||
|
extern const vfs_file_system_t nanocoap_fs_file_system;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* NET_NANOCOAP_FS_H */
|
||||||
|
/** @} */
|
@ -589,6 +589,25 @@ int nanocoap_sock_get_blockwise(nanocoap_sock_t *sock, const char *path,
|
|||||||
coap_blksize_t blksize,
|
coap_blksize_t blksize,
|
||||||
coap_blockwise_cb_t callback, void *arg);
|
coap_blockwise_cb_t callback, void *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a blockwise coap get request to the specified url, store
|
||||||
|
* the response in a buffer.
|
||||||
|
*
|
||||||
|
* @param[in] sock socket to use for the request
|
||||||
|
* @param[in] path Absolute URL pointer to source path
|
||||||
|
* @param[in] blksize sender suggested SZX for the COAP block request
|
||||||
|
* @param[in] offset Offset in bytes from the start of the resource
|
||||||
|
* @param[in] dst Target buffer
|
||||||
|
* @param[in] len Target buffer length
|
||||||
|
*
|
||||||
|
* @returns <0 on error
|
||||||
|
* @returns -EINVAL if an invalid url is provided
|
||||||
|
* @returns size of the response payload on success
|
||||||
|
*/
|
||||||
|
int nanocoap_sock_get_slice(nanocoap_sock_t *sock, const char *path,
|
||||||
|
coap_blksize_t blksize, size_t offset,
|
||||||
|
void *dst, size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Performs a blockwise coap get request to the specified url.
|
* @brief Performs a blockwise coap get request to the specified url.
|
||||||
*
|
*
|
||||||
|
70
sys/include/net/sock/config.h
Normal file
70
sys/include/net/sock/config.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
* 2018 Freie Universität Berlin
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup net_sock_util_conf SOCK utility functions compile configurations
|
||||||
|
* @ingroup net_sock_conf
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @brief sock utility configuration values
|
||||||
|
*
|
||||||
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NET_SOCK_CONFIG_H
|
||||||
|
#define NET_SOCK_CONFIG_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief maximum length of the scheme part for sock_urlsplit.
|
||||||
|
*
|
||||||
|
* Ensures a hard limit on the string iterator
|
||||||
|
* */
|
||||||
|
#ifndef CONFIG_SOCK_SCHEME_MAXLEN
|
||||||
|
#define CONFIG_SOCK_SCHEME_MAXLEN (16U)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief maximum length of host:port part for sock_urlsplit()
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_SOCK_HOSTPORT_MAXLEN
|
||||||
|
#define CONFIG_SOCK_HOSTPORT_MAXLEN (64U)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief maximum length path for sock_urlsplit()
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_SOCK_URLPATH_MAXLEN
|
||||||
|
#define CONFIG_SOCK_URLPATH_MAXLEN (64U)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Timeout in milliseconds for sock_dtls_establish_session()
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_SOCK_DTLS_TIMEOUT_MS
|
||||||
|
#define CONFIG_SOCK_DTLS_TIMEOUT_MS (1000U)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of DTLS handshake retries for sock_dtls_establish_session()
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_SOCK_DTLS_RETRIES
|
||||||
|
#define CONFIG_SOCK_DTLS_RETRIES (2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* NET_SOCK_CONFIG_H */
|
||||||
|
/** @} */
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "net/sock/udp.h"
|
#include "net/sock/udp.h"
|
||||||
#include "net/sock/tcp.h"
|
#include "net/sock/tcp.h"
|
||||||
|
#include "net/sock/config.h"
|
||||||
|
|
||||||
#ifdef MODULE_SOCK_DTLS
|
#ifdef MODULE_SOCK_DTLS
|
||||||
#include "net/credman.h"
|
#include "net/credman.h"
|
||||||
@ -296,49 +297,6 @@ int sock_dtls_establish_session(sock_udp_t *sock_udp, sock_dtls_t *sock_dtls,
|
|||||||
void *work_buf, size_t work_buf_len);
|
void *work_buf, size_t work_buf_len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup net_sock_util_conf SOCK utility functions compile configurations
|
|
||||||
* @ingroup net_sock_conf
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @brief maximum length of the scheme part for sock_urlsplit.
|
|
||||||
*
|
|
||||||
* Ensures a hard limit on the string iterator
|
|
||||||
* */
|
|
||||||
#ifndef CONFIG_SOCK_SCHEME_MAXLEN
|
|
||||||
#define CONFIG_SOCK_SCHEME_MAXLEN (16U)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief maximum length of host:port part for sock_urlsplit()
|
|
||||||
*/
|
|
||||||
#ifndef CONFIG_SOCK_HOSTPORT_MAXLEN
|
|
||||||
#define CONFIG_SOCK_HOSTPORT_MAXLEN (64U)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief maximum length path for sock_urlsplit()
|
|
||||||
*/
|
|
||||||
#ifndef CONFIG_SOCK_URLPATH_MAXLEN
|
|
||||||
#define CONFIG_SOCK_URLPATH_MAXLEN (64U)
|
|
||||||
#endif
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Timeout in milliseconds for sock_dtls_establish_session()
|
|
||||||
*/
|
|
||||||
#ifndef CONFIG_SOCK_DTLS_TIMEOUT_MS
|
|
||||||
#define CONFIG_SOCK_DTLS_TIMEOUT_MS (1000U)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of DTLS handshake retries for sock_dtls_establish_session()
|
|
||||||
*/
|
|
||||||
#ifndef CONFIG_SOCK_DTLS_RETRIES
|
|
||||||
#define CONFIG_SOCK_DTLS_RETRIES (2)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -61,7 +61,11 @@
|
|||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
#include "clist.h"
|
#include "clist.h"
|
||||||
#include "iolist.h"
|
#include "iolist.h"
|
||||||
|
#include "macros/utils.h"
|
||||||
#include "mtd.h"
|
#include "mtd.h"
|
||||||
|
#ifdef MODULE_NANOCOAP_FS
|
||||||
|
#include "net/sock/config.h"
|
||||||
|
#endif
|
||||||
#include "xfa.h"
|
#include "xfa.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -75,21 +79,12 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief MAX functions for internal use
|
* @brief MAX6 Function to get the largest of 6 values
|
||||||
* @{
|
|
||||||
*/
|
*/
|
||||||
#ifndef _MAX
|
#ifndef MAX6
|
||||||
#define _MAX(a, b) ((a) > (b) ? (a) : (b))
|
#define MAX6(a, b, c, d, e, f) MAX(MAX(MAX(MAX((a), (b)), MAX((c), (d))), (e)), (f))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MAX5
|
|
||||||
/**
|
|
||||||
* @brief MAX5 Function to get the largest of 5 values
|
|
||||||
*/
|
|
||||||
#define MAX5(a, b, c, d, e) _MAX(_MAX(_MAX((a), (b)), _MAX((c),(d))), (e))
|
|
||||||
#endif
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief VFS parameters for FAT
|
* @brief VFS parameters for FAT
|
||||||
* @{
|
* @{
|
||||||
@ -208,6 +203,21 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief VFS parameters for nanoCoAP FS
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#if defined(MODULE_NANOCOAP_FS) || DOXYGEN
|
||||||
|
# define NANOCOAP_FS_VFS_DIR_BUFFER_SIZE \
|
||||||
|
(4 + CONFIG_SOCK_URLPATH_MAXLEN) /**< sizeof(nanocoap_fs_dir_t) */
|
||||||
|
# define NANOCOAP_FS_VFS_FILE_BUFFER_SIZE \
|
||||||
|
(4 + CONFIG_SOCK_URLPATH_MAXLEN) /**< sizeof(nanocoap_fs_file_t) */
|
||||||
|
#else
|
||||||
|
# define NANOCOAP_FS_VFS_DIR_BUFFER_SIZE (1)
|
||||||
|
# define NANOCOAP_FS_VFS_FILE_BUFFER_SIZE (1)
|
||||||
|
#endif
|
||||||
|
/** @} */
|
||||||
|
|
||||||
#ifndef VFS_MAX_OPEN_FILES
|
#ifndef VFS_MAX_OPEN_FILES
|
||||||
/**
|
/**
|
||||||
* @brief Maximum number of simultaneous open files
|
* @brief Maximum number of simultaneous open files
|
||||||
@ -243,11 +253,12 @@ extern "C" {
|
|||||||
* @attention Put the check in the public header file (.h), do not put the check in the
|
* @attention Put the check in the public header file (.h), do not put the check in the
|
||||||
* implementation (.c) file.
|
* implementation (.c) file.
|
||||||
*/
|
*/
|
||||||
#define VFS_DIR_BUFFER_SIZE MAX5(FATFS_VFS_DIR_BUFFER_SIZE, \
|
#define VFS_DIR_BUFFER_SIZE MAX6(FATFS_VFS_DIR_BUFFER_SIZE, \
|
||||||
LITTLEFS_VFS_DIR_BUFFER_SIZE, \
|
LITTLEFS_VFS_DIR_BUFFER_SIZE, \
|
||||||
LITTLEFS2_VFS_DIR_BUFFER_SIZE, \
|
LITTLEFS2_VFS_DIR_BUFFER_SIZE, \
|
||||||
SPIFFS_VFS_DIR_BUFFER_SIZE, \
|
SPIFFS_VFS_DIR_BUFFER_SIZE, \
|
||||||
LWEXT4_VFS_DIR_BUFFER_SIZE \
|
LWEXT4_VFS_DIR_BUFFER_SIZE, \
|
||||||
|
NANOCOAP_FS_VFS_DIR_BUFFER_SIZE \
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -271,11 +282,12 @@ extern "C" {
|
|||||||
* @attention Put the check in the public header file (.h), do not put the check in the
|
* @attention Put the check in the public header file (.h), do not put the check in the
|
||||||
* implementation (.c) file.
|
* implementation (.c) file.
|
||||||
*/
|
*/
|
||||||
#define VFS_FILE_BUFFER_SIZE MAX5(FATFS_VFS_FILE_BUFFER_SIZE, \
|
#define VFS_FILE_BUFFER_SIZE MAX6(FATFS_VFS_FILE_BUFFER_SIZE, \
|
||||||
LITTLEFS_VFS_FILE_BUFFER_SIZE, \
|
LITTLEFS_VFS_FILE_BUFFER_SIZE, \
|
||||||
LITTLEFS2_VFS_FILE_BUFFER_SIZE,\
|
LITTLEFS2_VFS_FILE_BUFFER_SIZE, \
|
||||||
SPIFFS_VFS_FILE_BUFFER_SIZE, \
|
SPIFFS_VFS_FILE_BUFFER_SIZE, \
|
||||||
LWEXT4_VFS_FILE_BUFFER_SIZE \
|
LWEXT4_VFS_FILE_BUFFER_SIZE, \
|
||||||
|
NANOCOAP_FS_VFS_FILE_BUFFER_SIZE \
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ struct requestoptions {
|
|||||||
bool etag :1; /**< Request carries an Etag option */
|
bool etag :1; /**< Request carries an Etag option */
|
||||||
bool block2 :1; /**< Request carries a Block2 option */
|
bool block2 :1; /**< Request carries a Block2 option */
|
||||||
bool block1 :1; /**< Request carries a Block1 option */
|
bool block1 :1; /**< Request carries a Block1 option */
|
||||||
|
bool size2 :1; /**< Request carries a Size2 option */
|
||||||
} exists; /**< Structure holding flags of present request options */
|
} exists; /**< Structure holding flags of present request options */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -204,13 +205,15 @@ static ssize_t _get_file(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
|||||||
struct requestdata *request)
|
struct requestdata *request)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
uint32_t etag;
|
uint32_t etag, size_total;
|
||||||
|
|
||||||
coap_block1_t block2 = { .szx = CONFIG_NANOCOAP_BLOCK_SIZE_EXP_MAX };
|
coap_block1_t block2 = { .szx = CONFIG_NANOCOAP_BLOCK_SIZE_EXP_MAX };
|
||||||
{
|
{
|
||||||
struct stat stat;
|
struct stat stat;
|
||||||
if ((err = vfs_stat(request->namebuf, &stat)) < 0) {
|
if ((err = vfs_stat(request->namebuf, &stat)) < 0) {
|
||||||
return _error_handler(pdu, buf, len, err);
|
return _error_handler(pdu, buf, len, err);
|
||||||
}
|
}
|
||||||
|
size_total = stat.st_size;
|
||||||
stat_etag(&stat, &etag);
|
stat_etag(&stat, &etag);
|
||||||
}
|
}
|
||||||
if (request->options.exists.block2 && !coap_get_block2(pdu, &block2)) {
|
if (request->options.exists.block2 && !coap_get_block2(pdu, &block2)) {
|
||||||
@ -240,6 +243,11 @@ static ssize_t _get_file(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
|||||||
&block2);
|
&block2);
|
||||||
coap_block_slicer_init(&slicer, block2.blknum, coap_szx2size(block2.szx));
|
coap_block_slicer_init(&slicer, block2.blknum, coap_szx2size(block2.szx));
|
||||||
coap_opt_add_block2(pdu, &slicer, true);
|
coap_opt_add_block2(pdu, &slicer, true);
|
||||||
|
|
||||||
|
if (request->options.exists.block2) {
|
||||||
|
coap_opt_add_uint(pdu, COAP_OPT_SIZE2, size_total);
|
||||||
|
}
|
||||||
|
|
||||||
size_t resp_len = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD);
|
size_t resp_len = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD);
|
||||||
|
|
||||||
err = vfs_lseek(fd, slicer.start, SEEK_SET);
|
err = vfs_lseek(fd, slicer.start, SEEK_SET);
|
||||||
@ -692,6 +700,9 @@ ssize_t nanocoap_fileserver_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
|||||||
}
|
}
|
||||||
request.options.exists.block1 = true;
|
request.options.exists.block1 = true;
|
||||||
break;
|
break;
|
||||||
|
case COAP_OPT_SIZE2:
|
||||||
|
request.options.exists.size2 = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (opt.opt_num & 1) {
|
if (opt.opt_num & 1) {
|
||||||
errorcode = COAP_CODE_BAD_OPTION;
|
errorcode = COAP_CODE_BAD_OPTION;
|
||||||
|
322
sys/net/application_layer/nanocoap/fs.c
Normal file
322
sys/net/application_layer/nanocoap/fs.c
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 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 backend
|
||||||
|
*
|
||||||
|
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "net/nanocoap_sock.h"
|
||||||
|
#include "net/nanocoap/fs.h"
|
||||||
|
#include "net/nanocoap/link_format.h"
|
||||||
|
#include "net/sock/util.h"
|
||||||
|
#include "string_utils.h"
|
||||||
|
#include "vfs.h"
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG 0
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
static int nanocoap_fs_mount(vfs_mount_t *mountp)
|
||||||
|
{
|
||||||
|
nanocoap_fs_t *fs = mountp->private_data;
|
||||||
|
|
||||||
|
static_assert(VFS_FILE_BUFFER_SIZE >= sizeof(nanocoap_fs_file_t),
|
||||||
|
"nanocoap_fs_file_t must fit into VFS_FILE_BUFFER_SIZE");
|
||||||
|
static_assert(VFS_DIR_BUFFER_SIZE >= sizeof(nanocoap_fs_dir_t),
|
||||||
|
"nanocoap_fs_dir_t must fit into VFS_DIR_BUFFER_SIZE");
|
||||||
|
|
||||||
|
return nanocoap_sock_url_connect(fs->url, &fs->sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nanocoap_fs_umount(vfs_mount_t *mountp)
|
||||||
|
{
|
||||||
|
nanocoap_fs_t *fs = mountp->private_data;
|
||||||
|
|
||||||
|
nanocoap_sock_close(&fs->sock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fill_urlbuf(nanocoap_fs_t *fs, char dst[CONFIG_SOCK_URLPATH_MAXLEN],
|
||||||
|
const char *name, bool dir)
|
||||||
|
{
|
||||||
|
name += 1; /* skip leading '/' */
|
||||||
|
|
||||||
|
const char *extra = "";
|
||||||
|
if (dir) {
|
||||||
|
const char *end = name + strlen(name) - 1;
|
||||||
|
if (*end != '/') {
|
||||||
|
extra = "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((unsigned)snprintf(dst, CONFIG_SOCK_URLPATH_MAXLEN, "%s%s%s",
|
||||||
|
sock_urlpath(fs->url), name, extra) > CONFIG_SOCK_URLPATH_MAXLEN) {
|
||||||
|
DEBUG("nanocoap_fs: %s%s > %u bytes\n",
|
||||||
|
sock_urlpath(fs->url), name, CONFIG_SOCK_URLPATH_MAXLEN);
|
||||||
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nanocoap_fs_unlink(vfs_mount_t *mountp, const char *name)
|
||||||
|
{
|
||||||
|
nanocoap_fs_t *fs = mountp->private_data;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
mutex_lock(&fs->lock);
|
||||||
|
|
||||||
|
if ((res = _fill_urlbuf(fs, fs->urlbuf, name, true))) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("nanocoap_fs: delete %s\n", fs->urlbuf);
|
||||||
|
res = nanocoap_sock_delete(&fs->sock, fs->urlbuf);
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&fs->lock);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nanocoap_fs_open(vfs_file_t *filp, const char *name, int flags, mode_t mode)
|
||||||
|
{
|
||||||
|
nanocoap_fs_t *fs = filp->mp->private_data;
|
||||||
|
nanocoap_fs_file_t *file = (void *)filp->private_data.buffer;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
(void)mode;
|
||||||
|
|
||||||
|
if (flags != O_RDONLY) {
|
||||||
|
/* so far only read is implemented */
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = _fill_urlbuf(fs, file->urlbuf, name, false))) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("nanocoap_fs: open %s\n", file->urlbuf);
|
||||||
|
|
||||||
|
file->offset = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t nanocoap_fs_read(vfs_file_t *filp, void *dest, size_t nbytes)
|
||||||
|
{
|
||||||
|
nanocoap_fs_t *fs = filp->mp->private_data;
|
||||||
|
nanocoap_fs_file_t *file = (void *)filp->private_data.buffer;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
DEBUG("nanocoap_fs: read %"PRIuSIZE" bytes\n", nbytes);
|
||||||
|
|
||||||
|
res = nanocoap_sock_get_slice(&fs->sock, file->urlbuf, CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT,
|
||||||
|
file->offset, dest, nbytes);
|
||||||
|
if (res > 0) {
|
||||||
|
file->offset += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static off_t nanocoap_fs_lseek(vfs_file_t *filp, off_t off, int whence)
|
||||||
|
{
|
||||||
|
nanocoap_fs_file_t *file = (void *)filp->private_data.buffer;
|
||||||
|
|
||||||
|
switch (whence) {
|
||||||
|
case SEEK_SET:
|
||||||
|
file->offset = off;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
file->offset += off;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _block_cb(void *arg, coap_pkt_t *pkt)
|
||||||
|
{
|
||||||
|
struct stat *restrict buf = arg;
|
||||||
|
|
||||||
|
if (coap_get_code_class(pkt) != COAP_CLASS_SUCCESS) {
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->st_mode = S_IFREG;
|
||||||
|
|
||||||
|
uint32_t size = 0;
|
||||||
|
coap_opt_get_uint(pkt, COAP_OPT_SIZE2, &size);
|
||||||
|
buf->st_size = size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _query_server(nanocoap_sock_t *sock, const char *path,
|
||||||
|
struct stat *restrict arg)
|
||||||
|
{
|
||||||
|
uint8_t _buf[CONFIG_NANOCOAP_BLOCK_HEADER_MAX];
|
||||||
|
uint8_t *buf = _buf;
|
||||||
|
|
||||||
|
coap_pkt_t pkt = {
|
||||||
|
.hdr = (void *)buf,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t lastonum = 0;
|
||||||
|
|
||||||
|
buf += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_GET,
|
||||||
|
nanocoap_sock_next_msg_id(sock));
|
||||||
|
buf += coap_opt_put_uri_pathquery(buf, &lastonum, path);
|
||||||
|
buf += coap_opt_put_uint(buf, lastonum, COAP_OPT_BLOCK2, 0);
|
||||||
|
buf += coap_opt_put_uint(buf, COAP_OPT_BLOCK2, COAP_OPT_SIZE2, 0);
|
||||||
|
|
||||||
|
assert((uintptr_t)buf - (uintptr_t)pkt.hdr < sizeof(_buf));
|
||||||
|
|
||||||
|
pkt.payload = buf;
|
||||||
|
pkt.payload_len = 0;
|
||||||
|
|
||||||
|
return nanocoap_sock_request_cb(sock, &pkt, _block_cb, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nanocoap_fs_stat(vfs_mount_t *mountp, const char *restrict path,
|
||||||
|
struct stat *restrict buf)
|
||||||
|
{
|
||||||
|
nanocoap_fs_t *fs = mountp->private_data;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
mutex_lock(&fs->lock);
|
||||||
|
|
||||||
|
if ((res = _fill_urlbuf(fs, fs->urlbuf, path, false))) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dummy[4];
|
||||||
|
if (_query_server(&fs->sock, fs->urlbuf, buf) < 0) {
|
||||||
|
if ((res = _fill_urlbuf(fs, fs->urlbuf, path, true))) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nanocoap_sock_get_slice(&fs->sock, fs->urlbuf, COAP_BLOCKSIZE_16,
|
||||||
|
0, dummy, sizeof(dummy)) >= 0) {
|
||||||
|
buf->st_mode = S_IFDIR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&fs->lock);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nanocoap_fs_opendir(vfs_DIR *dirp, const char *dirname)
|
||||||
|
{
|
||||||
|
nanocoap_fs_t *fs = dirp->mp->private_data;
|
||||||
|
nanocoap_fs_dir_t *dir = (void *)dirp->private_data.buffer;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if ((res = _fill_urlbuf(fs, dir->urlbuf, dirname, true))) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("nanocoap_fs: opendir(%s)\n", dir->urlbuf);
|
||||||
|
|
||||||
|
dir->offset = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _dir_ctx {
|
||||||
|
vfs_dirent_t *dirent;
|
||||||
|
size_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _dir_cb(char *entry, void *arg)
|
||||||
|
{
|
||||||
|
struct _dir_ctx *ctx = arg;
|
||||||
|
|
||||||
|
if (ctx->offset) {
|
||||||
|
--ctx->offset;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *start = strchr(entry, '<');
|
||||||
|
if (start) {
|
||||||
|
char *end = strchr(entry, '>');
|
||||||
|
*end = '\0';
|
||||||
|
entry = start + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *end = entry + strlen(entry) - 1;
|
||||||
|
if (*end == '/') {
|
||||||
|
*end = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
char *basename = strrchr(entry, '/');
|
||||||
|
if (basename) {
|
||||||
|
entry = basename + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strscpy(ctx->dirent->d_name, entry, sizeof(ctx->dirent->d_name));
|
||||||
|
return -EINTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nanocoap_fs_readdir(vfs_DIR *dirp, vfs_dirent_t *entry)
|
||||||
|
{
|
||||||
|
nanocoap_fs_t *fs = dirp->mp->private_data;
|
||||||
|
nanocoap_fs_dir_t *dir = (void *)dirp->private_data.buffer;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
entry->d_ino = dir->offset;
|
||||||
|
|
||||||
|
struct _dir_ctx ctx = {
|
||||||
|
.dirent = entry,
|
||||||
|
.offset = dir->offset++,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = nanocoap_link_format_get(&fs->sock, dir->urlbuf, _dir_cb, &ctx);
|
||||||
|
if (res == -EINTR) {
|
||||||
|
/* we use this to abort listing early */
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const vfs_file_system_ops_t nanocoap_fs_ops = {
|
||||||
|
.stat = nanocoap_fs_stat,
|
||||||
|
.mount = nanocoap_fs_mount,
|
||||||
|
.umount = nanocoap_fs_umount,
|
||||||
|
.unlink = nanocoap_fs_unlink,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vfs_file_ops_t nanocoap_fs_file_ops = {
|
||||||
|
.lseek = nanocoap_fs_lseek,
|
||||||
|
.open = nanocoap_fs_open,
|
||||||
|
.read = nanocoap_fs_read,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vfs_dir_ops_t nanocoap_fs_dir_ops = {
|
||||||
|
.opendir = nanocoap_fs_opendir,
|
||||||
|
.readdir = nanocoap_fs_readdir,
|
||||||
|
};
|
||||||
|
|
||||||
|
const vfs_file_system_t nanocoap_fs_file_system = {
|
||||||
|
.f_op = &nanocoap_fs_file_ops,
|
||||||
|
.fs_op = &nanocoap_fs_ops,
|
||||||
|
.d_op = &nanocoap_fs_dir_ops,
|
||||||
|
};
|
@ -722,6 +722,107 @@ int nanocoap_sock_get_blockwise(nanocoap_sock_t *sock, const char *path,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t *ptr;
|
||||||
|
size_t len;
|
||||||
|
size_t offset;
|
||||||
|
size_t res;
|
||||||
|
} _buf_slice_t;
|
||||||
|
|
||||||
|
static int _2buf_slice(void *arg, size_t offset, uint8_t *buf, size_t len, int more)
|
||||||
|
{
|
||||||
|
_buf_slice_t *ctx = arg;
|
||||||
|
|
||||||
|
if (offset + len < ctx->offset) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset > ctx->offset + ctx->len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx->len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = ctx->offset - offset;
|
||||||
|
len = MIN(len - offset, ctx->len);
|
||||||
|
|
||||||
|
memcpy(ctx->ptr, buf + offset, len);
|
||||||
|
|
||||||
|
ctx->len -= len;
|
||||||
|
ctx->ptr += len;
|
||||||
|
ctx->offset += len;
|
||||||
|
ctx->res += len;
|
||||||
|
|
||||||
|
DEBUG("nanocoap: got %"PRIuSIZE" bytes, %"PRIuSIZE" bytes left (offset: %"PRIuSIZE")\n",
|
||||||
|
len, ctx->len, offset);
|
||||||
|
|
||||||
|
if (!more) {
|
||||||
|
ctx->len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned _num_blks(size_t offset, size_t len, coap_blksize_t szx)
|
||||||
|
{
|
||||||
|
uint16_t mask = coap_szx2size(szx) - 1;
|
||||||
|
uint8_t shift = szx + 4;
|
||||||
|
size_t end = offset + len;
|
||||||
|
|
||||||
|
unsigned num_blks = ((end >> shift) + !!(end & mask))
|
||||||
|
- ((offset >> shift) + !!(offset & mask));
|
||||||
|
return num_blks;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nanocoap_sock_get_slice(nanocoap_sock_t *sock, const char *path,
|
||||||
|
coap_blksize_t blksize, size_t offset,
|
||||||
|
void *dst, size_t len)
|
||||||
|
{
|
||||||
|
uint8_t buf[CONFIG_NANOCOAP_BLOCK_HEADER_MAX];
|
||||||
|
|
||||||
|
/* try to find optimal blocksize */
|
||||||
|
unsigned num_blocks = _num_blks(offset, len, blksize);
|
||||||
|
for (uint8_t szx = 0; szx < blksize; ++szx) {
|
||||||
|
if (_num_blks(offset, len, szx) <= num_blocks) {
|
||||||
|
blksize = szx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buf_slice_t dst_ctx = {
|
||||||
|
.ptr = dst,
|
||||||
|
.len = len,
|
||||||
|
.offset = offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
_block_ctx_t ctx = {
|
||||||
|
.callback = _2buf_slice,
|
||||||
|
.arg = &dst_ctx,
|
||||||
|
.more = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if CONFIG_NANOCOAP_SOCK_BLOCK_TOKEN
|
||||||
|
random_bytes(ctx.token, sizeof(ctx.token));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned num = offset >> (blksize + 4);
|
||||||
|
while (dst_ctx.len) {
|
||||||
|
DEBUG("nanocoap: fetching block %u\n", num);
|
||||||
|
|
||||||
|
int res = _fetch_block(sock, buf, sizeof(buf), path, blksize, num, &ctx);
|
||||||
|
if (res < 0) {
|
||||||
|
DEBUG("nanocoap: error fetching block %u: %d\n", num, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
num += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst_ctx.res;
|
||||||
|
}
|
||||||
|
|
||||||
int nanocoap_sock_url_connect(const char *url, nanocoap_sock_t *sock)
|
int nanocoap_sock_url_connect(const char *url, nanocoap_sock_t *sock)
|
||||||
{
|
{
|
||||||
char hostport[CONFIG_SOCK_HOSTPORT_MAXLEN];
|
char hostport[CONFIG_SOCK_HOSTPORT_MAXLEN];
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "compiler_hints.h"
|
#include "compiler_hints.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "macros/math.h"
|
||||||
#include "net/af.h"
|
#include "net/af.h"
|
||||||
#include "net/gnrc/ipv6.h"
|
#include "net/gnrc/ipv6.h"
|
||||||
#include "net/gnrc/ipv6/hdr.h"
|
#include "net/gnrc/ipv6/hdr.h"
|
||||||
@ -27,7 +28,7 @@
|
|||||||
#include "net/ipv6/hdr.h"
|
#include "net/ipv6/hdr.h"
|
||||||
#include "net/udp.h"
|
#include "net/udp.h"
|
||||||
#include "utlist.h"
|
#include "utlist.h"
|
||||||
#if IS_USED(MODULE_ZTIMER_USEC)
|
#if IS_USED(MODULE_ZTIMER_USEC) || IS_USED(MODULE_ZTIMER_MSEC)
|
||||||
#include "ztimer.h"
|
#include "ztimer.h"
|
||||||
#endif
|
#endif
|
||||||
#if IS_USED(MODULE_XTIMER)
|
#if IS_USED(MODULE_XTIMER)
|
||||||
@ -42,7 +43,7 @@ extern gnrc_pktsnip_t *gnrc_pktbuf_fuzzptr;
|
|||||||
gnrc_pktsnip_t *gnrc_sock_prevpkt = NULL;
|
gnrc_pktsnip_t *gnrc_sock_prevpkt = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if IS_USED(MODULE_XTIMER) || IS_USED(MODULE_ZTIMER_USEC)
|
#if IS_USED(MODULE_XTIMER) || IS_USED(MODULE_ZTIMER_USEC) || IS_USED(MODULE_ZTIMER_MSEC)
|
||||||
#define _TIMEOUT_MAGIC (0xF38A0B63U)
|
#define _TIMEOUT_MAGIC (0xF38A0B63U)
|
||||||
#define _TIMEOUT_MSG_TYPE (0x8474)
|
#define _TIMEOUT_MSG_TYPE (0x8474)
|
||||||
|
|
||||||
@ -127,6 +128,13 @@ ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
|
|||||||
timeout_timer.arg = reg;
|
timeout_timer.arg = reg;
|
||||||
ztimer_set(ZTIMER_USEC, &timeout_timer, timeout);
|
ztimer_set(ZTIMER_USEC, &timeout_timer, timeout);
|
||||||
}
|
}
|
||||||
|
#elif IS_USED(MODULE_ZTIMER_MSEC)
|
||||||
|
ztimer_t timeout_timer = { .base = { .next = NULL } };
|
||||||
|
if ((timeout != SOCK_NO_TIMEOUT) && (timeout != 0)) {
|
||||||
|
timeout_timer.callback = _callback_put;
|
||||||
|
timeout_timer.arg = reg;
|
||||||
|
ztimer_set(ZTIMER_MSEC, &timeout_timer, DIV_ROUND_INF(timeout, US_PER_MS));
|
||||||
|
}
|
||||||
#elif IS_USED(MODULE_XTIMER)
|
#elif IS_USED(MODULE_XTIMER)
|
||||||
xtimer_t timeout_timer = { .callback = NULL };
|
xtimer_t timeout_timer = { .callback = NULL };
|
||||||
|
|
||||||
@ -162,6 +170,8 @@ ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
|
|||||||
}
|
}
|
||||||
#if IS_USED(MODULE_ZTIMER_USEC)
|
#if IS_USED(MODULE_ZTIMER_USEC)
|
||||||
ztimer_remove(ZTIMER_USEC, &timeout_timer);
|
ztimer_remove(ZTIMER_USEC, &timeout_timer);
|
||||||
|
#elif IS_USED(MODULE_ZTIMER_MSEC)
|
||||||
|
ztimer_remove(ZTIMER_MSEC, &timeout_timer);
|
||||||
#elif IS_USED(MODULE_XTIMER)
|
#elif IS_USED(MODULE_XTIMER)
|
||||||
xtimer_remove(&timeout_timer);
|
xtimer_remove(&timeout_timer);
|
||||||
#endif
|
#endif
|
||||||
@ -169,7 +179,7 @@ ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
|
|||||||
case GNRC_NETAPI_MSG_TYPE_RCV:
|
case GNRC_NETAPI_MSG_TYPE_RCV:
|
||||||
pkt = msg.content.ptr;
|
pkt = msg.content.ptr;
|
||||||
break;
|
break;
|
||||||
#if IS_USED(MODULE_XTIMER) || IS_USED(MODULE_ZTIMER_USEC)
|
#if IS_USED(MODULE_XTIMER) || IS_USED(MODULE_ZTIMER_USEC) || IS_USED(MODULE_ZTIMER_MSEC)
|
||||||
case _TIMEOUT_MSG_TYPE:
|
case _TIMEOUT_MSG_TYPE:
|
||||||
if (msg.content.value == _TIMEOUT_MAGIC) {
|
if (msg.content.value == _TIMEOUT_MAGIC) {
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
|
@ -647,14 +647,17 @@ static int _ls_handler(int argc, char **argv)
|
|||||||
|
|
||||||
snprintf(path_name, sizeof(path_name), "%s/%s", path, entry.d_name);
|
snprintf(path_name, sizeof(path_name), "%s/%s", path, entry.d_name);
|
||||||
vfs_stat(path_name, &stat);
|
vfs_stat(path_name, &stat);
|
||||||
|
|
||||||
|
printf("%s", entry.d_name);
|
||||||
if (stat.st_mode & S_IFDIR) {
|
if (stat.st_mode & S_IFDIR) {
|
||||||
printf("%s/\n", entry.d_name);
|
printf("/");
|
||||||
} else if (stat.st_mode & S_IFREG) {
|
} else if (stat.st_mode & S_IFREG) {
|
||||||
printf("%s\t%lu B\n", entry.d_name, stat.st_size);
|
if (stat.st_size) {
|
||||||
|
printf("\t%lu B", stat.st_size);
|
||||||
|
}
|
||||||
++nfiles;
|
++nfiles;
|
||||||
} else {
|
|
||||||
printf("%s\n", entry.d_name);
|
|
||||||
}
|
}
|
||||||
|
puts("");
|
||||||
}
|
}
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
printf("total %u files\n", nfiles);
|
printf("total %u files\n", nfiles);
|
||||||
|
22
tests/net/nanocoap_fs/Makefile
Normal file
22
tests/net/nanocoap_fs/Makefile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
include ../Makefile.net_common
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Optionally include DNS support. This includes resolution of names at an
|
||||||
|
# upstream DNS server and the handling of RDNSS options in Router Advertisements
|
||||||
|
# to auto-configure that upstream DNS server.
|
||||||
|
# USEMODULE += sock_dns # include DNS client
|
||||||
|
# USEMODULE += gnrc_ipv6_nib_dns # include RDNSS option handling
|
||||||
|
|
||||||
|
USEMODULE += nanocoap_fs
|
||||||
|
|
||||||
|
# Required by test
|
||||||
|
USEMODULE += shell
|
||||||
|
USEMODULE += shell_cmds_default
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
38
tests/net/nanocoap_fs/Makefile.ci
Normal file
38
tests/net/nanocoap_fs/Makefile.ci
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
BOARD_INSUFFICIENT_MEMORY := \
|
||||||
|
arduino-duemilanove \
|
||||||
|
arduino-leonardo \
|
||||||
|
arduino-mega2560 \
|
||||||
|
arduino-nano \
|
||||||
|
arduino-uno \
|
||||||
|
atmega328p \
|
||||||
|
atmega328p-xplained-mini \
|
||||||
|
atmega8 \
|
||||||
|
atxmega-a3bu-xplained \
|
||||||
|
bluepill-stm32f030c8 \
|
||||||
|
i-nucleo-lrwan1 \
|
||||||
|
msb-430 \
|
||||||
|
msb-430h \
|
||||||
|
nucleo-c031c6 \
|
||||||
|
nucleo-f030r8 \
|
||||||
|
nucleo-f031k6 \
|
||||||
|
nucleo-f042k6 \
|
||||||
|
nucleo-f303k8 \
|
||||||
|
nucleo-f334r8 \
|
||||||
|
nucleo-l011k4 \
|
||||||
|
nucleo-l031k6 \
|
||||||
|
nucleo-l053r8 \
|
||||||
|
olimex-msp430-h1611 \
|
||||||
|
olimex-msp430-h2618 \
|
||||||
|
samd10-xmini \
|
||||||
|
slstk3400a \
|
||||||
|
stk3200 \
|
||||||
|
stm32f030f4-demo \
|
||||||
|
stm32f0discovery \
|
||||||
|
stm32f7508-dk \
|
||||||
|
stm32g0316-disco \
|
||||||
|
stm32l0538-disco \
|
||||||
|
telosb \
|
||||||
|
waspmote-pro \
|
||||||
|
weact-g030f6 \
|
||||||
|
z1 \
|
||||||
|
#
|
11
tests/net/nanocoap_fs/README.md
Normal file
11
tests/net/nanocoap_fs/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# nanoCoAP remote fs example
|
||||||
|
|
||||||
|
This allows to mount a remote fs that was exported via e.g. `nanocoap_fileserver`
|
||||||
|
or `aiocoap-fileserver`.
|
||||||
|
|
||||||
|
The test provides a `mount` command to mount a remote fs at a local mount point:
|
||||||
|
|
||||||
|
mount coap://[fe80::607f:b1ff:fef7:689c]/vfs /coap
|
||||||
|
|
||||||
|
This will mount the `vfs/` resource on the remote server as a local `/coap/`
|
||||||
|
directory. This can then be interacted with normal `vfs` commands such as `ls`.
|
89
tests/net/nanocoap_fs/main.c
Normal file
89
tests/net/nanocoap_fs/main.c
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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 tests
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief nanoCoAP fs test app
|
||||||
|
*
|
||||||
|
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "msg.h"
|
||||||
|
|
||||||
|
#include "net/nanocoap/fs.h"
|
||||||
|
#include "string_utils.h"
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
|
#define MAIN_QUEUE_SIZE (4)
|
||||||
|
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
|
||||||
|
|
||||||
|
static int _cmd_mount(int argc, char **argv)
|
||||||
|
{
|
||||||
|
static char url[64];
|
||||||
|
static char mp[64];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
printf("usage: %s <url> <path>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = strscpy(mp, argv[2], sizeof(mp))) < 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if ((res = strscpy(url, argv[1], sizeof(url))) < 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url[res] != '/') {
|
||||||
|
url[res] = '/';
|
||||||
|
if (res == sizeof(url)) {
|
||||||
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
url[++res] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static nanocoap_fs_t nanocoap_fs_desc = {
|
||||||
|
.url = url,
|
||||||
|
};
|
||||||
|
|
||||||
|
static vfs_mount_t _mount = {
|
||||||
|
.fs = &nanocoap_fs_file_system,
|
||||||
|
.mount_point = mp,
|
||||||
|
.private_data = &nanocoap_fs_desc,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = vfs_mount(&_mount);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const shell_command_t shell_commands[] = {
|
||||||
|
{ "mount", "Mount a remote fs", _cmd_mount },
|
||||||
|
{ NULL, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
/* for the thread running the shell */
|
||||||
|
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
@ -24,22 +24,22 @@
|
|||||||
#include "xtimer.h"
|
#include "xtimer.h"
|
||||||
#include "periph/hwrng.h"
|
#include "periph/hwrng.h"
|
||||||
|
|
||||||
#define LIMIT (20U)
|
#define NUM_BYTES (20U)
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
uint8_t buf[LIMIT];
|
uint8_t buf[NUM_BYTES];
|
||||||
|
|
||||||
puts("\nHWRNG peripheral driver test\n");
|
puts("\nHWRNG peripheral driver test\n");
|
||||||
printf("This test will print from 1 to %u random bytes about every "
|
printf("This test will print from 1 to %u random bytes about every "
|
||||||
"second\n\n", LIMIT);
|
"second\n\n", NUM_BYTES);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/* zero out buffer */
|
/* zero out buffer */
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
/* create random numbers */
|
/* create random numbers */
|
||||||
for (unsigned i = 1; i <= LIMIT; i++) {
|
for (unsigned i = 1; i <= NUM_BYTES; i++) {
|
||||||
printf("generating %u random byte(s)\n", i);
|
printf("generating %u random byte(s)\n", i);
|
||||||
hwrng_read(buf, i);
|
hwrng_read(buf, i);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user