Skip to content

Commit

Permalink
net: use downloader for coap downloads
Browse files Browse the repository at this point in the history
Integrate the improved downloader library into nRF Cloud.
Instead of using a custom downloader backend,
use downloader for coap downloads.
Also,
remove external_download_client support since it isn't used anymore.

Signed-off-by: Maximilian Deubel <[email protected]>
  • Loading branch information
maxd-nordic committed Jan 17, 2025
1 parent ffeb36d commit f9b7ac7
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 483 deletions.
55 changes: 25 additions & 30 deletions include/net/fota_download.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@ enum fota_download_evt_id {

/** FOTA download abandoned due to a cancellation request. */
FOTA_DOWNLOAD_EVT_CANCELLED,

/** Resume the download at offset.
* Only generated if @kconfig{CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL} is enabled.
*/
FOTA_DOWNLOAD_EVT_RESUME_OFFSET,
};

/**
Expand Down Expand Up @@ -152,6 +147,31 @@ int fota_download(const char *host, const char *file, const int *sec_tag_list,
uint8_t sec_tag_count, uint8_t pdn_id, size_t fragment_size,
const enum dfu_target_image_type expected_type);

/**@brief Download the given file with the specified image type from the given host.
*
* Identical to fota_download_start_with_image_type(),
* but with additional host configuration options.
*
* @param host Name of host to start downloading from. Can include scheme
* and port number, for example https://google.com:443
* @param file Path to the file you wish to download. See fota_download_any()
* for details on expected format.
* @param sec_tag Security tag you want to use with COAPS. Pass -1 to disable DTLS.
* @param pdn_id Packet Data Network ID to use for the download, or 0 to use the default.
* @param fragment_size Fragment size to be used for the download. If 0, no fragmentation is used.
* @param expected_type Type of firmware file to be downloaded and installed.
* @param host_cfg Additional host configuration options.
*
* @retval 0 If download has started successfully.
* @retval -EALREADY If download is already ongoing.
* @retval -E2BIG If sec_tag_count is larger than
* @kconfig{CONFIG_FOTA_DOWNLOAD_SEC_TAG_LIST_SIZE_MAX}
* Otherwise, a negative value is returned.
*/
int fota_download_with_host_cfg(const char *host, const char *file,
int sec_tag, uint8_t pdn_id, size_t fragment_size,
const enum dfu_target_image_type expected_type, const struct downloader_host_cfg *host_cfg);


/**@brief Start downloading the given file of any image type from the given host.
*
Expand Down Expand Up @@ -281,31 +301,6 @@ int fota_download_s0_active_get(bool *const s0_active);
*/
int fota_download_b1_file_parse(char *s0_s1_files);

/**@brief Start a FOTA download using an external download client.
* Requires @kconfig{CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL} to be enabled.
*
* @param host Name of host.
* @param file File path of the firmware image.
* @param expected_type Type of firmware image to be installed.
* @param image_size Size of the firmware image.
*
* @retval 0 If successful.
* Otherwise, a (negative) error code is returned.
*/
int fota_download_external_start(const char *host, const char *file,
const enum dfu_target_image_type expected_type,
const size_t image_size);

/**@brief Handle a download event from an external download client.
* Requires @kconfig{CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL} to be enabled.
*
* @param evt Download event.
*
* @retval 0 If successful.
* Otherwise, a (negative) error code is returned.
*/
int fota_download_external_evt_handle(struct downloader_evt const *const evt);

#ifdef __cplusplus
}
#endif
Expand Down
4 changes: 0 additions & 4 deletions subsys/net/lib/fota_download/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ config FOTA_DOWNLOAD_SEC_TAG_LIST_SIZE_MAX
help
Maximum size of the list of security tags used to store TLS credentials.

config FOTA_DOWNLOAD_EXTERNAL_DL
bool "Use external download events to perform FOTA updates"
select EXPERIMENTAL

module=FOTA_DOWNLOAD
module-dep=LOG
module-str=Firmware Over the Air Download
Expand Down
78 changes: 9 additions & 69 deletions subsys/net/lib/fota_download/src/fota_download.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@

LOG_MODULE_REGISTER(fota_download, CONFIG_FOTA_DOWNLOAD_LOG_LEVEL);

#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL)
static size_t ext_file_sz;
static size_t ext_rcvd_sz;
#endif

static fota_download_callback_t callback;
static const char *dl_host;
static const char *dl_file;
Expand Down Expand Up @@ -105,15 +100,6 @@ static void send_progress(int progress)
#endif
}

static void send_ext_resume(const size_t offset)
{
#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL)
const struct fota_download_evt evt = { .id = FOTA_DOWNLOAD_EVT_RESUME_OFFSET,
.resume_offset = offset };
callback(&evt);
#endif
}

static void stopped(void)
{
atomic_clear_bit(&flags, FLAG_DOWNLOADING);
Expand Down Expand Up @@ -143,27 +129,16 @@ static void dfu_target_callback_handler(enum dfu_target_evt_id evt)

static size_t file_size_get(size_t *size)
{
#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL)
*size = ext_file_sz;
return 0;
#endif
return downloader_file_size_get(&dl, size);
}

static size_t downloaded_size_get(size_t *size)
{
#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL)
*size = ext_rcvd_sz;
return 0;
#endif
return downloader_downloaded_size_get(&dl, size);
}

static int dl_cancel(void)
{
#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL)
return 0;
#endif
return downloader_cancel(&dl);
}

Expand Down Expand Up @@ -264,10 +239,6 @@ static int downloader_callback(const struct downloader_evt *event)
}
}

#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL)
ext_rcvd_sz += event->fragment.len;
#endif

err = dfu_target_write(event->fragment.buf, event->fragment.len);
if (err && err == -EINVAL) {
LOG_INF("Image refused");
Expand Down Expand Up @@ -321,7 +292,8 @@ static int downloader_callback(const struct downloader_evt *event)
/* In case of socket errors we can return 0 to retry/continue,
* or non-zero to stop
*/
if ((socket_retries_left) && (event->error == -ECONNRESET)) {
if ((socket_retries_left)
&& ((event->error == -ECONNRESET) || (event->error == -EAGAIN))) {
LOG_WRN("Download socket error. %d retries left...",
socket_retries_left);
socket_retries_left--;
Expand Down Expand Up @@ -371,11 +343,6 @@ static int downloader_callback(const struct downloader_evt *event)

static int get_from_offset(const size_t offset)
{
if (IS_ENABLED(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL)) {
send_ext_resume(offset);
return 0;
}

int err = downloader_get_with_host_and_file(&dl, &dl_host_cfg, dl_host, dl_file, offset);

if (err != 0) {
Expand Down Expand Up @@ -533,47 +500,20 @@ static void set_host_and_file(char const *const host, char const *const file)
dl_file = file;
}

#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL)
int fota_download_external_evt_handle(struct downloader_evt const *const evt)
{
return downloader_callback(evt);
}

int fota_download_external_start(const char *host, const char *file,
const enum dfu_target_image_type expected_type,
const size_t image_size)
int fota_download_with_host_cfg(const char *host, const char *file,
int sec_tag, uint8_t pdn_id, size_t fragment_size,
const enum dfu_target_image_type expected_type, const struct downloader_host_cfg *host_cfg)
{
if (host == NULL || file == NULL || callback == NULL || image_size == 0) {
return -EINVAL;
}

if (atomic_test_and_set_bit(&flags, FLAG_DOWNLOADING)) {
return -EALREADY;
}

atomic_clear_bit(&flags, FLAG_STOPPED);
atomic_clear_bit(&flags, FLAG_RESUME);
set_error_state(FOTA_DOWNLOAD_ERROR_CAUSE_NO_ERROR);

set_host_and_file(host, file);

socket_retries_left = CONFIG_FOTA_SOCKET_RETRIES;

img_type_expected = expected_type;
ext_file_sz = image_size;
ext_rcvd_sz = 0;

atomic_set_bit(&flags, FLAG_FIRST_FRAGMENT);

return 0;
dl_host_cfg = *host_cfg;
LOG_ERR("downloading %s/%s", host, file);
return fota_download_start_with_image_type(host, file, sec_tag,
pdn_id, fragment_size, expected_type);
}
#endif /* CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL */

int fota_download(const char *host, const char *file,
const int *sec_tag_list, uint8_t sec_tag_count, uint8_t pdn_id, size_t fragment_size,
const enum dfu_target_image_type expected_type)
{
__ASSERT_NO_MSG(!IS_ENABLED(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL));

if (host == NULL || file == NULL || callback == NULL) {
return -EINVAL;
Expand Down
1 change: 1 addition & 0 deletions subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_coap
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ endif # WIFI
config NRF_CLOUD_COAP_DOWNLOADS
bool "Download files using CoAP instead of HTTP [EXPERIMENTAL]"
depends on NRF_CLOUD_COAP
select DOWNLOADER_TRANSPORT_COAP
select EXPERIMENTAL
help
Use nRF Cloud CoAP's proxy download resource to download files for FOTA and P-GPS.
Expand Down
1 change: 0 additions & 1 deletion subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_fota
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ config NRF_CLOUD_FOTA_POLL
bool "FOTA job polling helpers (REST/CoAP)"
depends on !NRF_CLOUD_FOTA
depends on FOTA_DOWNLOAD
select FOTA_DOWNLOAD_EXTERNAL_DL if NRF_CLOUD_COAP_DOWNLOADS
help
When enabled, nRF Cloud FOTA job polling helpers will be built. These
functions make it easy to request, download, and handle modem, boot,
Expand Down
11 changes: 5 additions & 6 deletions subsys/net/lib/nrf_cloud/coap/include/nrf_cloud_coap_transport.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,17 @@ int nrf_cloud_coap_transport_pause(struct nrf_cloud_coap_client *const client);
*/
int nrf_cloud_coap_transport_resume(struct nrf_cloud_coap_client *const client);

/**@brief Get the CoAP options required to perform a proxy download.
/**@brief Get the URI required to perform a proxy download.
*
* @param opt_accept Option to be populated with COAP_OPTION_ACCEPT details.
* @param opt_proxy_uri Option to be populated with COAP_OPTION_PROXY_URI details.
* @param uri Buffer to store the URI.
* @param uri_len Length of the URI buffer.
* @param host Download host.
* @param path Download file path.
*
* @return 0 if successful, otherwise a negative error code.
*/
int nrf_cloud_coap_transport_proxy_dl_opts_get(struct coap_client_option *const opt_accept,
struct coap_client_option *const opt_proxy_uri,
char const *const host, char const *const path);
int nrf_cloud_coap_transport_proxy_dl_uri_get(char *const uri, size_t uri_len,
char const *const host, char const *const path);

/**@brief Check if device is connected and authorized to use nRF Cloud CoAP.
*
Expand Down
40 changes: 12 additions & 28 deletions subsys/net/lib/nrf_cloud/coap/src/nrf_cloud_coap_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -928,49 +928,33 @@ int nrf_cloud_coap_transport_resume(struct nrf_cloud_coap_client *const client)
#define PROXY_URI_DL_HTTPS_LEN (sizeof(PROXY_URI_DL_HTTPS) - 1)
#define PROXY_URI_DL_SEP "/"
#define PROXY_URI_DL_SEP_LEN (sizeof(PROXY_URI_DL_SEP) - 1)
#define PROXY_URI_ADDED_LEN (PROXY_URI_DL_HTTPS_LEN + PROXY_URI_DL_SEP_LEN)

int nrf_cloud_coap_transport_proxy_dl_opts_get(struct coap_client_option *const opt_accept,
struct coap_client_option *const opt_proxy_uri,
char const *const host, char const *const path)
int nrf_cloud_coap_transport_proxy_dl_uri_get(char *const uri, size_t uri_len,
char const *const host, char const *const path)
{
__ASSERT_NO_MSG(opt_accept != NULL);
__ASSERT_NO_MSG(opt_proxy_uri != NULL);
__ASSERT_NO_MSG(uri != NULL);
__ASSERT_NO_MSG(host != NULL);
__ASSERT_NO_MSG(path != NULL);

size_t uri_idx = 0;
size_t host_len = strlen(host);
size_t path_len = strlen(path);

opt_accept->code = COAP_OPTION_ACCEPT;
opt_accept->len = 1;
opt_accept->value[0] = COAP_CONTENT_FORMAT_TEXT_PLAIN;
const size_t needed_len =
PROXY_URI_DL_HTTPS_LEN + host_len + PROXY_URI_DL_SEP_LEN + path_len;

opt_proxy_uri->code = COAP_OPTION_PROXY_URI;
opt_proxy_uri->len = host_len + path_len + PROXY_URI_ADDED_LEN;

if (opt_proxy_uri->len > CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE) {
if (needed_len > uri_len) {
LOG_ERR("Host and path for CoAP proxy GET is too large: %u bytes",
opt_proxy_uri->len);
LOG_INF("Increase CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE, current value: %d",
CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE);
needed_len);
return -E2BIG;
}

/* We don't want a NULL terminated string, so just copy the data to create the full URI */
memcpy(&opt_proxy_uri->value[uri_idx], PROXY_URI_DL_HTTPS, PROXY_URI_DL_HTTPS_LEN);
uri_idx += PROXY_URI_DL_HTTPS_LEN;

memcpy(&opt_proxy_uri->value[uri_idx], host, host_len);
uri_idx += host_len;

memcpy(&opt_proxy_uri->value[uri_idx], PROXY_URI_DL_SEP, PROXY_URI_DL_SEP_LEN);
uri_idx += PROXY_URI_DL_SEP_LEN;

memcpy(&opt_proxy_uri->value[uri_idx], path, path_len);
memcpy(uri, PROXY_URI_DL_HTTPS, PROXY_URI_DL_HTTPS_LEN);
memcpy(&uri[PROXY_URI_DL_HTTPS_LEN], host, host_len);
memcpy(&uri[PROXY_URI_DL_HTTPS_LEN + host_len], PROXY_URI_DL_SEP, PROXY_URI_DL_SEP_LEN);
memcpy(&uri[PROXY_URI_DL_HTTPS_LEN + host_len + PROXY_URI_DL_SEP_LEN], path, path_len);

LOG_DBG("Proxy URI: %.*s", opt_proxy_uri->len, opt_proxy_uri->value);
LOG_DBG("Proxy URI: %.*s", needed_len, uri);

return 0;
}
10 changes: 0 additions & 10 deletions subsys/net/lib/nrf_cloud/include/nrf_cloud_download.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,6 @@ struct nrf_cloud_download_data {
/* Downloader data */
struct downloader *dl;
};

#if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS)
/* Track the received bytes for CoAP downloads */
size_t coap_rcvd_bytes;
/* Offset used when resuming a download */
size_t resume_offset;
#endif
};

/** @brief Start download. Only one download at a time is allowed. FOTA downloads have priority.
Expand All @@ -71,9 +64,6 @@ int nrf_cloud_download_start(struct nrf_cloud_download_data *const cloud_dl);
*/
void nrf_cloud_download_cancel(void);

/** @brief Resume a CoAP download at the provided offset. */
int nrf_cloud_download_coap_offset_resume(const size_t offset);

/** @brief Reset the active download state. Call when download has ended. */
void nrf_cloud_download_end(void);

Expand Down
Loading

0 comments on commit f9b7ac7

Please sign in to comment.