diff mbox series

[5/8] downloader: make use of channel_curl

Message ID 20180305154006.18122-5-christian.storm@siemens.com
State Accepted
Headers show
Series [1/8] channel_curl: add support for Basic Auth credentials | expand

Commit Message

Storm, Christian March 5, 2018, 3:40 p.m. UTC
Instead of the downloader having an own cURL binding
implementation, make use of the generic channel_curl.

Signed-off-by: Christian Storm <christian.storm@siemens.com>
---
 Kconfig              |   2 +-
 corelib/downloader.c | 347 +++++++--------------------------------------------
 2 files changed, 49 insertions(+), 300 deletions(-)

Comments

Stefano Babic March 7, 2018, 10:47 a.m. UTC | #1
On 05/03/2018 16:40, Christian Storm wrote:
> Instead of the downloader having an own cURL binding
> implementation, make use of the generic channel_curl.
> 
> Signed-off-by: Christian Storm <christian.storm@siemens.com>
> ---
>  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 <stdio.h>
>  #include <stdlib.h>
> -#include <stdint.h>
> -#include <unistd.h>
> -#include <string.h>
>  #include <errno.h>
> -#include <ctype.h>
>  #include <getopt.h>
> -#include <sys/types.h>
> -#include <fcntl.h>
> -#include <sys/stat.h>
>  
> -#include <curl/curl.h>
> -
> -#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);
> 

Code is becoming much more cleaner and readable and silly duplication
are removed - thanks !

Reviewed-by: Stefano Babic <sbabic@denx.de>

Best regards,
Stefano Babic
diff mbox series

Patch

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 <stdio.h>
 #include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <string.h>
 #include <errno.h>
-#include <ctype.h>
 #include <getopt.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/stat.h>
 
-#include <curl/curl.h>
-
-#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);