From patchwork Mon Mar 5 15:40:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Storm, Christian" X-Patchwork-Id: 881551 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:400c:c0c::23f; helo=mail-wr0-x23f.google.com; envelope-from=swupdate+bncbdd6bwv65qpbbqgk6xkakgqe33yc62i@googlegroups.com; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=siemens.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.b="FJp+4z3N"; dkim-atps=neutral Received: from mail-wr0-x23f.google.com (mail-wr0-x23f.google.com [IPv6:2a00:1450:400c:c0c::23f]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zw4024mTkz9sZf for ; Tue, 6 Mar 2018 02:41:54 +1100 (AEDT) Received: by mail-wr0-x23f.google.com with SMTP id q15sf11373329wra.22 for ; Mon, 05 Mar 2018 07:41:54 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1520264512; cv=pass; d=google.com; s=arc-20160816; b=YGGzeHCwpkMlZbRpEqE+fvgnhKYjmXrNSIoIfnciKZCy4lvJyRl4gB9HRlpo9+uAH8 1LzYfErsREQb8OdNDNWvVOBVtZo52EgxraAlAwhTT8iAZ03iPqbZSATrnOirE6Fo1zjC xaTh+8g5YJAdzmiAInVrJZV+nV1xIIBWWHv3nuJD5NfuD8xZI51c+obtlGL7gLKcW3S0 09H+HNTNF/vTJh29yaYQ74nevLYGSX/QcbroAGnBdSMJOs2Z/1PJnC4i8IqaM5hiBPuC fZbEEgxmaj7fM78tXUp8ONB3R0D9g7FIsvU3J3JsX05kepNRNnYLiBDxoqml3UsD4cvM UT6w== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:arc-authentication-results :arc-message-signature:mime-version:sender:dkim-signature :arc-authentication-results; bh=v8BR/5EyGhjNDhrYZDSLeL7T6fLXhz+cluVELTy85Qk=; b=JDvkkppKgKkoyLoyJVWwDBeeWqTrhj9bhjaKJpY5fnKCqSWek53dThyygcO6PsWgSO E6aLqE5E4fzvYT1uu57AkmPytGI1xfodqxaeJ1JKIzDAO2CWEReHjBnXAHzZMbIES2VP FdKKS7Qhl6MueoIgUqpHA8w97FkC8ez9lYiJ+8KXEUkJwcwi1DIli4vtAkqsl4mfyvpY BiNSR+MFy8WApAHEg77nQz3z/nTuAy1UPndOY/3eDs79r+xRJnfm74Jl60+te4MkOkab 43YETDdkbVIcsuUqpjr0iFlH18HVN2YSOdzuGld2jzNcvasxV7ge8mWw59Xi4gql8pSO zNuw== ARC-Authentication-Results: i=2; gmr-mx.google.com; spf=pass (google.com: domain of christian.storm@siemens.com designates 192.35.17.14 as permitted sender) smtp.mailfrom=christian.storm@siemens.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20161025; h=sender:mime-version:from:to:cc:subject:date:message-id:in-reply-to :references:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-subscribe:list-unsubscribe; bh=v8BR/5EyGhjNDhrYZDSLeL7T6fLXhz+cluVELTy85Qk=; b=FJp+4z3NQnIlVWYxfMUgYt5/0AI5GH9ZkHBs8sYCwq9LgZ6Oc7Ff0GXJDvWcuOASDH G0NCBxH7DJqhMEFBQLY6DMwdjtUGCyqQQp9ibfSzv5hve9a/N31nW0FUxRxb44uSpC88 VUsEYjRyHTTcNSNVzjaBs0aZAJzp6MX0w7DyKBrSAAfR+bZMAexRjsHMyEF9mVdzMJrz 7fGrVTeMp5JBDGkKN9KSM/rutjAu9DFhsu6Fdk3IkwYjJmflGpA5QMw+BWxow/V0rFoH fbyHybqcFHGm7d3jhTg53UDATFsl39H8G6vwkUd5AjHXjz03Oh1sXEwWzG5FEqpyuyQf V37w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=sender:x-gm-message-state:mime-version:from:to:cc:subject:date :message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-spam-checked-in-group:list-post:list-help:list-archive :list-subscribe:list-unsubscribe; bh=v8BR/5EyGhjNDhrYZDSLeL7T6fLXhz+cluVELTy85Qk=; b=TtsC7qboSlezHWOiDBKP0ZIpOsdE4oB6J9yP8K//B/z29UuHi8qyP6gI3CoLUxNWqq EWkgfWB4jrvVVGSI/CbjR9Wa2JX/cKI9+A6csed2BPZvJR28XW5ci7/BBPPnyFDPE7LM Mr2+zv3pTp+m/G32DYQcCEQ1gKqySFTh33NvYy4TBPFhtKS3KyCB51cch9UQsdoi3Wux 3Ad48BNeN3OgIVIvKMKcIotl6kq5S2stOcBvaH3bAGcjCOCS2J5Nn6hOLRRj2ux6Tuev nDmazUX4Xk5d24uC++Kwvvnf86qyDHWSoJFos2trPuiIdId9nlEiyrMRblEIxJrPirBD daiQ== Sender: swupdate@googlegroups.com X-Gm-Message-State: AElRT7EhAzbmAg4vpipyn+Ki2VHY5Q8eNZgNIi9JPo1ptFNI48l8haal +iAl46GohPxy0esAqTl7K/E= X-Google-Smtp-Source: AG47ELv4Pd4tWrO4zPP3lUhW2v2zqVJZ1QmpyVfuxjSuBGdv0cVLWTMzPBr//hdz/Tof+VbKYErMgw== X-Received: by 10.28.63.139 with SMTP id m133mr142635wma.3.1520264512317; Mon, 05 Mar 2018 07:41:52 -0800 (PST) MIME-Version: 1.0 X-BeenThere: swupdate@googlegroups.com Received: by 10.223.135.246 with SMTP id c51ls4458251wrc.11.gmail; Mon, 05 Mar 2018 07:41:51 -0800 (PST) X-Received: by 10.223.150.47 with SMTP id b44mr1326151wra.7.1520264511722; Mon, 05 Mar 2018 07:41:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1520264511; cv=none; d=google.com; s=arc-20160816; b=dj/LdHfaOK+GSoQ98FBeTL/c9b07Zp1rQWqkPzFWWOe/4npbXPvTyROqRoYgxNu/v7 +KPMmBvRSzuW9ch8sMgIc5q3hXHD34dlusk99s4n3nHQvzDYXG1PBQpaw72DlmAoxfbL NJu7Lz38/6xD3G/M/S7wzoSFiHjBlED70frdCvHmvrrxdkSp8ypEQSo0lkEtuiyqhiac 9TTFaj0l+aZDMuxn7v2rWwuwYNGYzeUQIVEIFyoTMeXBtLG/kqSftiqt7vXYnIM/+7BI JxX9BVksEZsy6mTGx9seNrRZRWXJgyj5VblM9/qZzBBZkuFTwJ0tj86NNkV/b9hTIud5 2Mxg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=hMDwQlPIaDwaQWJZ5mrhn0cFFhMNUBmIk4yiZ5a9qow=; b=aVcWLvMf0Sb7YYWkhF086cmHuDRs4lOYC8AAgE1cVVGYstZUs+beoVerU2RGMrkooL YSCkcda/6IXP3DAAjgAj7lZqTgPDZ3bm4fIoJlRDTOsWvjKXG3ab9tMJSX+/Dh7eof1l RQBxFidrbpGmWc9xdzSA9vgpVKGCJb7+hNJ3JokoVGDACcpKxrOWNIDkT+/1RWgdqJgs WQkJPHnIgc09kqOqqy6h5j1aBXZ5VFCT0WMAM400i+FLpqs6IHPcI6jYOz4TCXLqIfZs 4JJzEJgciW7RVF6R1Nq+exOo7Ucgy4V3Lq+xFiXVmmGZVxe3rYHnpCeVdyfsX5QzzJj2 PETA== ARC-Authentication-Results: i=1; gmr-mx.google.com; spf=pass (google.com: domain of christian.storm@siemens.com designates 192.35.17.14 as permitted sender) smtp.mailfrom=christian.storm@siemens.com Received: from david.siemens.de (david.siemens.de. [192.35.17.14]) by gmr-mx.google.com with ESMTPS id a138si249965wmd.0.2018.03.05.07.41.51 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 05 Mar 2018 07:41:51 -0800 (PST) Received-SPF: pass (google.com: domain of christian.storm@siemens.com designates 192.35.17.14 as permitted sender) client-ip=192.35.17.14; Received: from mail3.siemens.de (mail3.siemens.de [139.25.208.14]) by david.siemens.de (8.15.2/8.15.2) with ESMTPS id w25Ffphw021116 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Mon, 5 Mar 2018 16:41:51 +0100 Received: from MD1KR9XC.ww002.siemens.net ([139.25.69.202]) by mail3.siemens.de (8.15.2/8.15.2) with ESMTP id w25FfRYK022466; Mon, 5 Mar 2018 16:41:51 +0100 From: Christian Storm To: swupdate@googlegroups.com Cc: Christian Storm Subject: [swupdate] [PATCH 5/8] downloader: make use of channel_curl Date: Mon, 5 Mar 2018 16:40:03 +0100 Message-Id: <20180305154006.18122-5-christian.storm@siemens.com> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180305154006.18122-1-christian.storm@siemens.com> References: <20180305154006.18122-1-christian.storm@siemens.com> X-Original-Sender: christian.storm@siemens.com X-Original-Authentication-Results: gmr-mx.google.com; spf=pass (google.com: domain of christian.storm@siemens.com designates 192.35.17.14 as permitted sender) smtp.mailfrom=christian.storm@siemens.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , Instead of the downloader having an own cURL binding implementation, make use of the generic channel_curl. Signed-off-by: Christian Storm Reviewed-by: Stefano Babic --- Kconfig | 2 +- corelib/downloader.c | 347 +++++++-------------------------------------------- 2 files changed, 49 insertions(+), 300 deletions(-) diff --git a/Kconfig b/Kconfig index fe2f5ae..ed5559c 100644 --- a/Kconfig +++ b/Kconfig @@ -286,7 +286,7 @@ config DOWNLOAD bool "Enable image downloading" default n depends on HAVE_LIBCURL - select CURL + select CHANNEL_CURL help Enable update from image URL using libcurl. The stream is sent via IPC to the installer as it is done for other interfaces. diff --git a/corelib/downloader.c b/corelib/downloader.c index 108a6f6..23471f1 100644 --- a/corelib/downloader.c +++ b/corelib/downloader.c @@ -5,29 +5,17 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#include #include -#include -#include -#include #include -#include #include -#include -#include -#include -#include - -#include "bsdqueue.h" #include "util.h" -#include "swupdate.h" -#include "installer.h" #include "network_ipc.h" +#include "download_interface.h" +#include "channel.h" +#include "channel_curl.h" #include "parselib.h" -#include "swupdate_status.h" #include "swupdate_settings.h" -#include "download_interface.h" #define SETSTRING(p, v) do { \ if (p) \ @@ -37,30 +25,13 @@ /* * Number of seconds while below low speed - * limit before aborting - * it can be overwritten by -t + * limit before aborting. It can be overwritten + * by -t command line flag. */ #define DL_LOWSPEED_TIME 300 #define DL_DEFAULT_RETRIES 3 -static int cnt = 0; - -struct dwl_options { - char *url; - unsigned int retries; - unsigned int timeout; - char *auth; -}; - -/* notify download progress each second */ -#define MINIMAL_PROGRESS_INTERVAL 1 - -struct dlprogress { - double lastruntime; - CURL *curl; -}; - static struct option long_options[] = { {"url", required_argument, NULL, 'u'}, {"retries", required_argument, NULL, 'r'}, @@ -68,242 +39,37 @@ static struct option long_options[] = { {"authentification", required_argument, NULL, 'a'}, {NULL, 0, NULL, 0}}; - -/* - * Callback from the libcurl API to progress meter function - * This function gets called by libcurl instead of its internal equivalent. - */ -static int download_info(void *p, - curl_off_t dltotal, curl_off_t dlnow, - curl_off_t __attribute__ ((__unused__)) ultotal, - curl_off_t __attribute__ ((__unused__)) ulnow) -{ - struct dlprogress *dlp = (struct dlprogress *)p; - CURL *curl = dlp->curl; - double curtime = 0; - curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &curtime); - - if ((curtime - dlp->lastruntime) >= MINIMAL_PROGRESS_INTERVAL) { - dlp->lastruntime = curtime; - INFO("Received : %" CURL_FORMAT_CURL_OFF_T " / %" - CURL_FORMAT_CURL_OFF_T, dlnow, dltotal); - } - - return 0; -} - -/* for libcurl older than 7.32.0 (CURLOPT_PROGRESSFUNCTION) */ -static int legacy_download_info(void *p, - double dltotal, double dlnow, - double ultotal, double ulnow) -{ - return download_info(p, - (curl_off_t)dltotal, - (curl_off_t)dlnow, - (curl_off_t)ultotal, - (curl_off_t)ulnow); -} - -/* - * Callback from the libcurl API - * It is called any time a chunk of data is received - * to transfer it via IPC to the installer - */ -static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) -{ - int ret; - int fd; - - if (!nmemb) - return 0; - if (!userp) { - ERROR("Failure IPC stream file descriptor \n"); - return -EFAULT; - } - - fd = *(int *)userp; - ret = ipc_send_data(fd, buffer, size * nmemb); - if (ret < 0) { - ERROR("Failure writing into IPC Stream\n"); - return ret; - } - cnt += size * nmemb; - - return nmemb; -} - -/* Minimum bytes/sec, else connection is broken */ -#define DL_LOWSPEED_BYTES 8 - -/* - * libcurl options (see easy interface in libcurl documentation) - * are grouped together into this function - */ -static void set_option_common(CURL *curl_handle, - unsigned long lowspeed_time, - struct dlprogress *prog) -{ - int ret; - - prog->lastruntime = 0; - prog->curl = curl_handle; - - curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "swupdate"); - - curl_easy_setopt(curl_handle, CURLOPT_PROGRESSFUNCTION, legacy_download_info); - curl_easy_setopt(curl_handle, CURLOPT_PROGRESSDATA, prog); -#if LIBCURL_VERSION_NUM >= 0x072000 - /* xferinfo was introduced in 7.32.0, no earlier libcurl versions will - compile as they won't have the symbols around. - - If built with a newer libcurl, but running with an older libcurl: - curl_easy_setopt() will fail in run-time trying to set the new - callback, making the older callback get used. - - New libcurls will prefer the new callback and instead use that one - even if both callbacks are set. */ - curl_easy_setopt(curl_handle, CURLOPT_XFERINFOFUNCTION, download_info); - curl_easy_setopt(curl_handle, CURLOPT_XFERINFODATA, prog); -#endif - curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L); - - curl_easy_setopt(curl_handle, CURLOPT_LOW_SPEED_LIMIT, DL_LOWSPEED_BYTES); - curl_easy_setopt(curl_handle, CURLOPT_LOW_SPEED_TIME, lowspeed_time); - - /* enable TCP keep-alive for this transfer */ - ret = curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPALIVE, 1L); - if (ret == CURLE_UNKNOWN_OPTION) { - TRACE("No keep alive (unsupported in curl)"); - return; - } - - /* keep-alive idle time to 240 seconds */ - curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPIDLE, 240L); - - /* interval time between keep-alive probes: 120 seconds */ - curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPINTVL, 120L); -} - /* - * This provide a pull from an external server - * It si not thought to work with local (file://) - * for that, the -i option is used. + * This provides a pull from an external server + * It is not thought to work with local (file://) + * files. For that, the -i option is used. */ -static RECOVERY_STATUS download_from_url(char *image_url, unsigned int retries, - unsigned long lowspeed_time, char *auth) +static RECOVERY_STATUS download_from_url(channel_data_t* channel_data) { - CURL *curl_handle; - CURLcode res = CURLE_GOT_NOTHING; - int fd; - int attempt = 10; - int result; - double dummy; - unsigned long long dwlbytes = 0; - unsigned int i; - struct dlprogress progress; - - - /* - * Maybe daemon is not yet started, - * try several times - */ - while (--attempt) { - fd = ipc_inst_start(); - if (fd > 0) - break; - sleep(1); - } - - if (fd < 0) { - ERROR("Error getting IPC: %s\n", strerror(errno)); + channel_t *channel = channel_new(); + if (channel->open(channel, channel_data) != CHANNEL_OK) { + free(channel); return FAILURE; } - errno = 0; - TRACE("download from url started : %s", image_url); - if (!image_url || !strlen(image_url)) { - ERROR("Image URL not provided... aborting download and update\n"); - return FAILURE; - } - - /* We are starting a download */ + TRACE("Image download started : %s", channel_data->url); notify(DOWNLOAD, 0, INFOLEVEL, NULL); - curl_global_init(CURL_GLOBAL_ALL); - curl_handle = curl_easy_init(); - if (!curl_handle) { - /* something very bad, it should never happen */ - ERROR("FAULT: no handle from libcurl"); - return FAILURE; - } - - /* Set URL */ - if (curl_easy_setopt(curl_handle, CURLOPT_URL, image_url) != CURLE_OK) { - TRACE("Runs out of memory: serious internal error"); - return FAILURE; - } - - /* Set Authentification */ - if (auth && curl_easy_setopt(curl_handle, CURLOPT_USERPWD, auth) != CURLE_OK) { - TRACE("Runs out of memory: serious internal error"); - return FAILURE; - } - - curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); - curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &fd); - set_option_common(curl_handle, lowspeed_time, &progress); - - TRACE("Image download started : %s", image_url); - - for (i = 0; (res != CURLE_OK); i++) { - /* if resume, set the offset */ - if (i) { - TRACE("Connection with server interrupted, try RESUME after %llu", - dwlbytes); - if (curl_easy_setopt(curl_handle,CURLOPT_RESUME_FROM_LARGE, - dwlbytes) != CURLE_OK) { - TRACE("CURLOPT_RESUME_FROM_LARGE not implemented"); - break; - } - - /* motivation: router restart, DNS reconfiguration */ - sleep(20); - } - res = curl_easy_perform(curl_handle); - - /* if size cannot be determined, exit because no resume is possible */ - if (curl_easy_getinfo(curl_handle, - CURLINFO_SIZE_DOWNLOAD, - &dummy) != CURLE_OK) - break; - - dwlbytes += dummy; - - /* Check if max attempts is reached */ - if (retries && (i >= retries)) - break; - - } - - curl_easy_cleanup(curl_handle); - curl_global_cleanup(); - - if (res == CURLE_OK) { - result = ipc_wait_for_complete(NULL); - } else { - INFO("Error : %s", curl_easy_strerror(res)); + RECOVERY_STATUS result = SUCCESS; + channel_op_res_t chanresult = channel->get_file(channel, channel_data, FD_USE_IPC); + if (chanresult != CHANNEL_OK) { result = FAILURE; } - - ipc_end(fd); - + ipc_wait_for_complete(NULL); + channel->close(channel); + free(channel); return result; } static int download_settings(void *elem, void __attribute__ ((__unused__)) *data) { - struct dwl_options *opt = (struct dwl_options *)data; - char tmp[128]; + channel_data_t *opt = (channel_data_t *)data; + char tmp[SWUPDATE_GENERAL_STRING_SIZE]; GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "url", tmp); if (strlen(tmp)) { @@ -320,7 +86,7 @@ static int download_settings(void *elem, void __attribute__ ((__unused__)) *dat get_field(LIBCFG_PARSER, elem, "retries", &opt->retries); get_field(LIBCFG_PARSER, elem, "timeout", - &opt->timeout); + &opt->low_speed_timeout); return 0; } @@ -338,40 +104,36 @@ void download_print_help(void) DL_DEFAULT_RETRIES, DL_LOWSPEED_TIME); } +static channel_data_t channel_options = { + .source = SOURCE_DOWNLOADER, + .debug = false, + .retries = DL_DEFAULT_RETRIES, + .low_speed_timeout = DL_LOWSPEED_TIME +}; + int start_download(const char *fname, int argc, char *argv[]) { - struct dwl_options options; - unsigned int attempt; - int choice = 0; - RECOVERY_STATUS result; - - memset(&options, 0, sizeof(options)); - - options.retries = DL_DEFAULT_RETRIES; - options.timeout = DL_LOWSPEED_TIME; - options.auth = NULL; - if (fname) { - read_module_settings(fname, "download", download_settings, - &options); + read_module_settings(fname, "download", download_settings, &channel_options); } /* reset to optind=1 to parse download's argument vector */ optind = 1; + int choice = 0; while ((choice = getopt_long(argc, argv, "t:u:r:a:", long_options, NULL)) != -1) { switch (choice) { case 't': - options.timeout = strtoul(optarg, NULL, 10); + channel_options.low_speed_timeout = strtoul(optarg, NULL, 10); break; case 'u': - SETSTRING(options.url, optarg); + SETSTRING(channel_options.url, optarg); break; case 'a': - SETSTRING(options.auth, optarg); + SETSTRING(channel_options.auth, optarg); break; case 'r': - options.retries = strtoul(optarg, NULL, 10); + channel_options.retries = strtoul(optarg, NULL, 10); break; case '?': default: @@ -379,34 +141,21 @@ int start_download(const char *fname, int argc, char *argv[]) } } - result = FAILURE; - - /* - * Maybe we need a different option as retries - * to check if an updated must be retried - */ - for (attempt = 0;; attempt++) { - result = download_from_url(options.url, options.retries, - options.timeout, options.auth); - if (result != FAILURE) { - ipc_message msg; - if (ipc_postupdate(&msg) != 0) { - result = FAILURE; - } else { - result = msg.type == ACK ? result : FAILURE; - } - break; + RECOVERY_STATUS result = download_from_url(&channel_options); + if (result != FAILURE) { + ipc_message msg; + if (ipc_postupdate(&msg) != 0) { + result = FAILURE; + } else { + result = msg.type == ACK ? result : FAILURE; } + } - if (options.retries > 0 && attempt >= options.retries) - break; - - /* - * motivation: slow connection, download_from_url fetched half the - * image, then aborted due to lowspeed_timeout, if we retry immediately - * we would just waste our bandwidth. Useful for A/B images. - */ - sleep(60); + if (channel_options.url != NULL) { + free(channel_options.url); + } + if (channel_options.auth != NULL) { + free(channel_options.auth); } exit(result == SUCCESS ? EXIT_SUCCESS : result);