From f9b7ac72d8cb7f7bbb6aa035bb56a872a83d9b13 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Wed, 15 Jan 2025 10:38:01 +0100 Subject: [PATCH] net: use downloader for coap downloads 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 --- include/net/fota_download.h | 55 ++- subsys/net/lib/fota_download/Kconfig | 4 - .../net/lib/fota_download/src/fota_download.c | 78 +--- .../net/lib/nrf_cloud/Kconfig.nrf_cloud_coap | 1 + .../net/lib/nrf_cloud/Kconfig.nrf_cloud_fota | 1 - .../coap/include/nrf_cloud_coap_transport.h | 11 +- .../coap/src/nrf_cloud_coap_transport.c | 40 +-- .../nrf_cloud/include/nrf_cloud_download.h | 10 - .../lib/nrf_cloud/src/nrf_cloud_download.c | 333 ++---------------- .../lib/nrf_cloud/src/nrf_cloud_fota_poll.c | 23 -- 10 files changed, 73 insertions(+), 483 deletions(-) diff --git a/include/net/fota_download.h b/include/net/fota_download.h index 6a45cbf18580..f5f02cc1aaa1 100644 --- a/include/net/fota_download.h +++ b/include/net/fota_download.h @@ -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, }; /** @@ -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. * @@ -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 diff --git a/subsys/net/lib/fota_download/Kconfig b/subsys/net/lib/fota_download/Kconfig index 5c99846fa9a8..c43daa4c159a 100644 --- a/subsys/net/lib/fota_download/Kconfig +++ b/subsys/net/lib/fota_download/Kconfig @@ -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 diff --git a/subsys/net/lib/fota_download/src/fota_download.c b/subsys/net/lib/fota_download/src/fota_download.c index b206124c424e..727c60d8131f 100644 --- a/subsys/net/lib/fota_download/src/fota_download.c +++ b/subsys/net/lib/fota_download/src/fota_download.c @@ -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; @@ -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); @@ -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); } @@ -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"); @@ -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--; @@ -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) { @@ -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; diff --git a/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_coap b/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_coap index e82968c574f6..b2d191926f4a 100644 --- a/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_coap +++ b/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_coap @@ -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. diff --git a/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_fota b/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_fota index 95a9c8779f9c..088aaee9cd0d 100644 --- a/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_fota +++ b/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_fota @@ -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, diff --git a/subsys/net/lib/nrf_cloud/coap/include/nrf_cloud_coap_transport.h b/subsys/net/lib/nrf_cloud/coap/include/nrf_cloud_coap_transport.h index ec46ae2402ef..3dc8762cb843 100644 --- a/subsys/net/lib/nrf_cloud/coap/include/nrf_cloud_coap_transport.h +++ b/subsys/net/lib/nrf_cloud/coap/include/nrf_cloud_coap_transport.h @@ -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. * diff --git a/subsys/net/lib/nrf_cloud/coap/src/nrf_cloud_coap_transport.c b/subsys/net/lib/nrf_cloud/coap/src/nrf_cloud_coap_transport.c index 83bf54716fde..cccad4684ecf 100644 --- a/subsys/net/lib/nrf_cloud/coap/src/nrf_cloud_coap_transport.c +++ b/subsys/net/lib/nrf_cloud/coap/src/nrf_cloud_coap_transport.c @@ -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; } diff --git a/subsys/net/lib/nrf_cloud/include/nrf_cloud_download.h b/subsys/net/lib/nrf_cloud/include/nrf_cloud_download.h index 285f170ad3da..1d3322d891aa 100644 --- a/subsys/net/lib/nrf_cloud/include/nrf_cloud_download.h +++ b/subsys/net/lib/nrf_cloud/include/nrf_cloud_download.h @@ -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. @@ -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); diff --git a/subsys/net/lib/nrf_cloud/src/nrf_cloud_download.c b/subsys/net/lib/nrf_cloud/src/nrf_cloud_download.c index c4077146749a..4ef663ba2dfb 100644 --- a/subsys/net/lib/nrf_cloud/src/nrf_cloud_download.c +++ b/subsys/net/lib/nrf_cloud/src/nrf_cloud_download.c @@ -34,30 +34,15 @@ static K_MUTEX_DEFINE(active_dl_mutex); static struct nrf_cloud_download_data active_dl = { .type = NRF_CLOUD_DL_TYPE_NONE }; #if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS) -#define ACPT_IDX 0 -#define PRXY_IDX 1 -#define OPT_CNT 2 -/* CoAP option array */ -static struct coap_client_option cc_opts[OPT_CNT] = {0}; /* CoAP client to be used for file downloads */ static struct nrf_cloud_coap_client coap_client; -/* Workqueue item used to resume a downlaod */ -static struct k_work_delayable resume_work; - -static void resume_work_fn(struct k_work *unused); - -static int coap_dl_init(void) -{ - k_work_init_delayable(&resume_work, resume_work_fn); - return nrf_cloud_coap_transport_init(&coap_client); -} int nrf_cloud_download_handle_coap_auth(int socket) { int err = 0; struct nrf_cloud_coap_client *client = &coap_client; - /* initialize a temporary client */ + /* initialize client */ err = nrf_cloud_coap_transport_init(client); if (err) { LOG_ERR("Failed to initialize CoAP client, error: %d", err); @@ -65,8 +50,10 @@ int nrf_cloud_download_handle_coap_auth(int socket) } /* we are already connected using the given socket */ + k_mutex_lock(&client->mutex, K_FOREVER); client->sock = socket; client->cc.fd = socket; + k_mutex_unlock(&client->mutex); /* authenticate */ err = nrf_cloud_coap_transport_authenticate(client); @@ -75,230 +62,30 @@ int nrf_cloud_download_handle_coap_auth(int socket) return err; } - /* clean up temporary client */ + /* clean up client */ k_mutex_lock(&client->mutex, K_FOREVER); client->sock = -1; client->cc.fd = -1; + client->authenticated = false; k_mutex_unlock(&client->mutex); return 0; } -static int coap_dl_connect_and_auth(void) -{ - int ret = nrf_cloud_coap_transport_connect(&coap_client); - - if (ret) { - LOG_ERR("CoAP connect failed, error; %d", ret); - return -EIO; - } - - ret = nrf_cloud_coap_transport_authenticate(&coap_client); - if (ret) { - LOG_ERR("CoAP authentication failed, error; %d", ret); - return -EACCES; - } - - return 0; -} - -static int fota_dl_evt_send(const struct downloader_evt *evt) -{ -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) - return fota_download_external_evt_handle(evt); -#endif - return -ENOTSUP; -} - -static int coap_dl_event_send(struct nrf_cloud_download_data const *const dl, - const struct downloader_evt *const evt) -{ - /* Send events as if we are the downoad_client */ - if (dl->type == NRF_CLOUD_DL_TYPE_FOTA) { - return fota_dl_evt_send(evt); - } else if (dl->type == NRF_CLOUD_DL_TYPE_DL_CLIENT) { - return dl->dl->cfg.callback(evt); - } - - return -EINVAL; -} - -static int coap_dl_disconnect(void) -{ - return nrf_cloud_coap_transport_disconnect(&coap_client); -} - -static void coap_dl_cb(int16_t result_code, size_t offset, const uint8_t *payload, size_t len, - bool last_block, void *user_data) -{ - int ret; - bool send_closed_evt = false; - bool send_done_evt = last_block; - bool stop_on_err = false; - struct nrf_cloud_download_data *dl = (struct nrf_cloud_download_data *)user_data; - struct downloader_evt evt = {0}; - - LOG_DBG("CoAP result: %d, offset: 0x%X, len: 0x%X, last_block: %d", - result_code, offset, len, last_block); - - if (result_code == COAP_RESPONSE_CODE_CONTENT) { - evt.id = DOWNLOADER_EVT_FRAGMENT; - evt.fragment.buf = payload; - evt.fragment.len = len; - } else if (result_code == -ECANCELED) { - LOG_DBG("CoAP request canceled"); - /* This is not actually an error, just use the error event to indicate that - * the transfer has been canceled - */ - evt.id = DOWNLOADER_EVT_ERROR; - evt.error = -ECANCELED; - (void)coap_dl_event_send(dl, &evt); - return; - } else if (result_code != COAP_RESPONSE_CODE_OK) { - LOG_ERR("Unexpected CoAP result: %d", result_code); - LOG_DBG("CoAP response: %.*s", len, payload); - evt.id = DOWNLOADER_EVT_ERROR; - /* Use -ECONNRESET to trigger retry mechanism used by fota_download and - * the P-GPS download event handler - */ - evt.error = -ECONNRESET; - stop_on_err = true; - } - - ret = coap_dl_event_send(dl, &evt); - - if (evt.id == DOWNLOADER_EVT_FRAGMENT) { - if (ret == 0) { - /* Fragment was successfully processed */ - dl->coap_rcvd_bytes += len; - } else if ((ret == -1) && (dl->type == NRF_CLOUD_DL_TYPE_FOTA)) { - /* For FOTA, -1 on a fragment event requires a closed event - * that will generate a request for restart. - */ - send_closed_evt = true; - send_done_evt = false; - ret = 0; - } - } else if ((ret == 0) && (evt.error == -ECONNRESET)) { - /* Retry if the event handler returned zero during an error event */ - dl->resume_offset = dl->coap_rcvd_bytes; - k_work_schedule(&resume_work, K_SECONDS(1)); - return; - } - - if (ret || stop_on_err) { - send_closed_evt = true; - send_done_evt = false; - stop_on_err = true; - } - - if (send_done_evt) { - LOG_INF("Download complete"); - - memset(&evt, 0, sizeof(evt)); - evt.id = DOWNLOADER_EVT_DONE; - - ret = coap_dl_event_send(dl, &evt); - if (ret) { - /* Send a closed event on error */ - send_closed_evt = true; - stop_on_err = true; - } - - ret = coap_dl_disconnect(); - if (ret && (ret != -ENOTCONN)) { - LOG_WRN("Failed to disconnect CoAP transport, error: %d", ret); - } - - if (dl->type == NRF_CLOUD_DL_TYPE_FOTA) { - /* fota_download expects a closed event when the download is done */ - send_closed_evt = true; - } - } - - if (send_closed_evt) { - memset(&evt, 0, sizeof(evt)); - evt.id = DOWNLOADER_EVT_STOPPED; - (void)coap_dl_event_send(dl, &evt); - } - - if (stop_on_err) { - LOG_ERR("CoAP download error, stopping download"); - nrf_cloud_download_end(); - } -} - -#define MAX_RETRIES 5 -#define PROXY_RSC_OFFSET_TMPLT NRF_CLOUD_COAP_PROXY_RSC "?offset=%u" -#define PROXY_RSC_BUF_SZ sizeof(PROXY_RSC_OFFSET_TMPLT) + 10 -static int coap_dl_start(struct nrf_cloud_download_data *const dl, const size_t offset) -{ - static char rsc_path_offset[PROXY_RSC_BUF_SZ]; - - int err; - int retry = 0; - struct coap_client *cc = &coap_client.cc; - - struct coap_client_request request = { - .method = COAP_METHOD_GET, - .confirmable = true, - .path = NRF_CLOUD_COAP_PROXY_RSC, - .fmt = COAP_CONTENT_FORMAT_APP_OCTET_STREAM, - .payload = NULL, - .len = 0, - .cb = coap_dl_cb, - .user_data = dl, - .options = cc_opts, - .num_options = OPT_CNT - }; - - if (offset > 0) { - /* Use the offset parameter in the resource path */ - err = snprintk(rsc_path_offset, sizeof(rsc_path_offset), - PROXY_RSC_OFFSET_TMPLT, offset); - if ((err < 0) || (err >= sizeof(rsc_path_offset))) { - LOG_ERR("Could not format CoAP proxy download resource"); - return -EIO; - } - request.path = rsc_path_offset; - } - - while ((err = coap_client_req(cc, cc->fd, NULL, &request, NULL)) == -EAGAIN) { - if (retry++ > MAX_RETRIES) { - LOG_ERR("Timeout waiting for CoAP client to be available"); - return -ETIMEDOUT; - } - LOG_DBG("CoAP client busy"); - k_sleep(K_MSEC(500)); - } - - if (err == 0) { - LOG_DBG("Sent CoAP download request, offset: %u", offset); - } else { - LOG_ERR("Error sending CoAP request: %d", err); - } - - return err; -} - static int coap_dl(struct nrf_cloud_download_data *const dl) { + static char proxy_uri[CONFIG_FOTA_DOWNLOAD_RESOURCE_LOCATOR_LENGTH]; #if defined(CONFIG_FOTA_DOWNLOAD) && defined(CONFIG_NRF_CLOUD_FOTA_TYPE_BOOT_SUPPORTED) - static char buf[CONFIG_FOTA_DOWNLOAD_RESOURCE_LOCATOR_LENGTH]; + char buf[CONFIG_FOTA_DOWNLOAD_RESOURCE_LOCATOR_LENGTH]; #endif const char *file_path = dl->path; - int ret = coap_dl_init(); + int ret = 0; if (ret) { LOG_ERR("Failed to initialize CoAP download, error: %d", ret); return ret; } - ret = coap_dl_connect_and_auth(); - if (ret) { - return ret; - } - #if defined(CONFIG_FOTA_DOWNLOAD) && defined(CONFIG_NRF_CLOUD_FOTA_TYPE_BOOT_SUPPORTED) if (dl->type == NRF_CLOUD_DL_TYPE_FOTA) { /* Copy file path to modifiable buffer and check for a bootloader file */ @@ -311,94 +98,24 @@ static int coap_dl(struct nrf_cloud_download_data *const dl) } } #endif - /* Reset the received count */ - dl->coap_rcvd_bytes = 0; - dl->resume_offset = 0; - - /* Get the options for the proxy download */ - ret = nrf_cloud_coap_transport_proxy_dl_opts_get(&cc_opts[ACPT_IDX], - &cc_opts[PRXY_IDX], - dl->host, file_path); + ret = nrf_cloud_coap_transport_proxy_dl_uri_get( + proxy_uri, ARRAY_SIZE(proxy_uri), dl->host, file_path); if (ret) { - LOG_ERR("Failed to set CoAP options, error: %d", ret); + LOG_ERR("Failed to get CoAP proxy URL, error: %d", ret); return ret; } - if (dl->type == NRF_CLOUD_DL_TYPE_FOTA) { -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) - ret = fota_download_external_start(dl->host, file_path, dl->fota.expected_type, - (size_t)dl->fota.img_sz); - if (ret) { - LOG_ERR("Failed to start FOTA download, error: %d", ret); - return ret; - } -#else - return -ENOTSUP; -#endif - } - - return coap_dl_start(dl, 0); -} - -int nrf_cloud_download_coap_offset_resume(const size_t offset) -{ - int err = 0; - - k_mutex_lock(&active_dl_mutex, K_FOREVER); - - if ((active_dl.type == NRF_CLOUD_DL_TYPE_FOTA) || - (active_dl.type == NRF_CLOUD_DL_TYPE_DL_CLIENT)) { - active_dl.resume_offset = offset; - k_work_schedule(&resume_work, K_SECONDS(1)); - } else if (active_dl.type == NRF_CLOUD_DL_TYPE_NONE) { - LOG_ERR("No active download, cannot resume"); - err = -ENODEV; - } else { - LOG_ERR("Invalid download type (%d), cannot resume", active_dl.type); - err = -EINVAL; - } - - k_mutex_unlock(&active_dl_mutex); - - return err; -} - -static void resume_work_fn(struct k_work *unused) -{ - int ret; - - if (active_dl.type == NRF_CLOUD_DL_TYPE_NONE) { - LOG_ERR("No active download, cannot resume"); - return; - } - - /* Ensure current request is canceled */ - coap_client_cancel_requests(&coap_client.cc); - - ret = coap_dl_connect_and_auth(); - if (ret == 0) { - LOG_DBG("Resuming download at offset: %u", active_dl.resume_offset); - ret = coap_dl_start(&active_dl, active_dl.resume_offset); - } - - /* On failure, send the events required to generate the error/done status */ - if (ret) { - struct downloader_evt evt = {0}; - - LOG_ERR("Failed to resume CoAP download"); - - /* Send a non-recoverable error event (not ECONN) */ - evt.id = DOWNLOADER_EVT_ERROR; - evt.error = -EIO; - (void)coap_dl_event_send(&active_dl, &evt); + struct downloader_host_cfg host_cfg = { + .cid = true, + .auth_cb = nrf_cloud_download_handle_coap_auth, + .proxy_uri = proxy_uri, + }; - /* Send a closed event to ensure the terminal fota_download event is generated */ - if (active_dl.type == NRF_CLOUD_DL_TYPE_FOTA) { - memset(&evt, 0, sizeof(evt)); - evt.id = DOWNLOADER_EVT_STOPPED; - (void)coap_dl_event_send(&active_dl, &evt); - } - } + return fota_download_with_host_cfg("coaps://" CONFIG_NRF_CLOUD_COAP_SERVER_HOSTNAME, + "proxy", dl->dl_host_conf.sec_tag_count ? + dl->dl_host_conf.sec_tag_list[0] : -1, + dl->dl_host_conf.pdn_id, dl->dl_host_conf.range_override, + dl->fota.expected_type, &host_cfg); } #endif /* NRF_CLOUD_COAP_DOWNLOADS */ @@ -460,10 +177,6 @@ static int dl_start(struct nrf_cloud_download_data *const cloud_dl) static int dl_disconnect(struct nrf_cloud_download_data *const dl) { -#if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS) - return coap_dl_disconnect(); -#endif /* CONFIG_NRF_CLOUD_COAP_DOWNLOADS */ - return downloader_cancel(dl->dl); } @@ -511,10 +224,6 @@ void nrf_cloud_download_cancel(void) void nrf_cloud_download_end(void) { -#if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS) - coap_dl_disconnect(); -#endif - k_mutex_lock(&active_dl_mutex, K_FOREVER); active_dl_reset(); k_mutex_unlock(&active_dl_mutex); diff --git a/subsys/net/lib/nrf_cloud/src/nrf_cloud_fota_poll.c b/subsys/net/lib/nrf_cloud/src/nrf_cloud_fota_poll.c index 0b893b0a833e..b0173b25721d 100644 --- a/subsys/net/lib/nrf_cloud/src/nrf_cloud_fota_poll.c +++ b/subsys/net/lib/nrf_cloud/src/nrf_cloud_fota_poll.c @@ -212,29 +212,6 @@ static void http_fota_dl_handler(const struct fota_download_evt *evt) case FOTA_DOWNLOAD_EVT_PROGRESS: LOG_DBG("FOTA download percent: %d%%", evt->progress); break; - case FOTA_DOWNLOAD_EVT_RESUME_OFFSET: - LOG_DBG("FOTA download resume at offset: %u", evt->resume_offset); - /* Event is only applicable if CoAP downloads are enabled */ -#if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS) - int err = nrf_cloud_download_coap_offset_resume(evt->resume_offset); - - if (err) { - LOG_ERR("Failed to resume download, error: %d", err); - nrf_cloud_download_end(); - fota_status = NRF_CLOUD_FOTA_FAILED; - fota_status_details = FOTA_STATUS_DETAILS_DL_ERR; - - if (ctx_ptr->is_nonblocking) { - k_work_cancel_delayable(&ctx_ptr->timeout_work); - ctx_ptr->status_fn(fota_status, fota_status_details); - - (void)update_job_status(ctx_ptr); - } else { - k_sem_give(&fota_download_sem); - } - } -#endif /* CONFIG_NRF_CLOUD_COAP_DOWNLOADS */ - break; default: break; }