diff mbox series

[v2] channel_curl: Add maximum download speed limit

Message ID 20210924134922.2712134-1-sava.jakovljev@teufel.de
State Accepted
Headers show
Series [v2] channel_curl: Add maximum download speed limit | expand

Commit Message

Sava Jakovljev Sept. 24, 2021, 1:49 p.m. UTC
* Extend Suricatta and general server with options to set download speed
  limit.
* Add 'n' short and 'max-download-speed' long command line option for
  setting download speed limit.
* Add 'maximum-download-speed' option in configuration file.
* Document new feature and provide configuration file example.

Signed-off-by: Sava Jakovljev <sava.jakovljev@teufel.de>
---
 corelib/channel_curl.c              |  9 +++++++++
 corelib/downloader.c                |  3 ++-
 doc/source/swupdate.rst             |  8 ++++++++
 examples/configuration/swupdate.cfg |  8 ++++++--
 include/channel_curl.h              |  1 +
 suricatta/common.c                  |  4 ++++
 suricatta/server_general.c          | 12 ++++++++++--
 suricatta/server_hawkbit.c          | 15 +++++++++++----
 8 files changed, 51 insertions(+), 9 deletions(-)

--
2.31.1

Comments

Stefano Babic Sept. 24, 2021, 2:19 p.m. UTC | #1
On 24.09.21 15:49, Sava Jakovljev wrote:
> * Extend Suricatta and general server with options to set download speed
>    limit.
> * Add 'n' short and 'max-download-speed' long command line option for
>    setting download speed limit.
> * Add 'maximum-download-speed' option in configuration file.
> * Document new feature and provide configuration file example.
> 
> Signed-off-by: Sava Jakovljev <sava.jakovljev@teufel.de>
> ---
>   corelib/channel_curl.c              |  9 +++++++++
>   corelib/downloader.c                |  3 ++-
>   doc/source/swupdate.rst             |  8 ++++++++
>   examples/configuration/swupdate.cfg |  8 ++++++--
>   include/channel_curl.h              |  1 +
>   suricatta/common.c                  |  4 ++++
>   suricatta/server_general.c          | 12 ++++++++++--
>   suricatta/server_hawkbit.c          | 15 +++++++++++----
>   8 files changed, 51 insertions(+), 9 deletions(-)
> 
> diff --git a/corelib/channel_curl.c b/corelib/channel_curl.c
> index 0761811..ff2053d 100644
> --- a/corelib/channel_curl.c
> +++ b/corelib/channel_curl.c
> @@ -1104,6 +1104,15 @@ channel_op_res_t channel_get_file(channel_t *this, void *data)
>   		goto cleanup_header;
>   	}
> 
> +	if (channel_data->max_download_speed &&
> +			curl_easy_setopt(channel_curl->handle,
> +				CURLOPT_MAX_RECV_SPEED_LARGE,
> +				channel_data->max_download_speed) != CURLE_OK) {
> +		ERROR("Set channel download speed limit failed.");
> +		result = CHANNEL_EINIT;
> +		goto cleanup_header;
> +	}
> +
>   	download_callback_data_t download_data;
>   	if (channel_enable_download_progress_tracking(channel_curl,
>   				channel_data->url,
> diff --git a/corelib/downloader.c b/corelib/downloader.c
> index 3d0a0a5..8596694 100644
> --- a/corelib/downloader.c
> +++ b/corelib/downloader.c
> @@ -105,7 +105,8 @@ static channel_data_t channel_options = {
>   	.debug = false,
>   	.retries = DL_DEFAULT_RETRIES,
>   	.low_speed_timeout = DL_LOWSPEED_TIME,
> -	.headers_to_send = NULL
> +	.headers_to_send = NULL,
> +	.max_download_speed = 0 // Unlimited download speed is default.
>   };
> 
>   int start_download(const char *fname, int argc, char *argv[])
> diff --git a/doc/source/swupdate.rst b/doc/source/swupdate.rst
> index 5af52f1..a81b87a 100644
> --- a/doc/source/swupdate.rst
> +++ b/doc/source/swupdate.rst
> @@ -665,6 +665,14 @@ Mandatory arguments are marked with '\*':
>   |                         |          | value to be sent with every HTTP request   |
>   |                         |          | made.                                      |
>   +-------------------------+----------+--------------------------------------------+
> +| -n <value>              | string   | Maximum download speed to be used.         |
> +|                         |          | Value be specified in kB/s, B/s, MB/s      |
> +|                         |          | or GB/s. Examples:                         |
> +|                         |          | -n 100k : Set limit to 100 kB/s.           |
> +|                         |          | -n 500  : Set limit to 500 B/s.            |
> +|                         |          | -n 2M   : Set limit to 1 M/s.              |
> +|                         |          | -n 1G   : Set limit to 1 G/s.              |
> ++-------------------------+----------+--------------------------------------------+
> 
> 
>   systemd Integration
> diff --git a/examples/configuration/swupdate.cfg b/examples/configuration/swupdate.cfg
> index 39a4401..ba36a31 100644
> --- a/examples/configuration/swupdate.cfg
> +++ b/examples/configuration/swupdate.cfg
> @@ -18,7 +18,7 @@
>   #	 		  enable sending logs to syslog daemon
>   # public-key-file	: string
>   #			  file with public key for
> -#			  image verification
> +#			  image verification
>   # mtd-blacklist		: list integers
>   #			  MTD devices where SWUpdate
>   #			  must not try to check for UBI filesystem.
> @@ -123,7 +123,7 @@ identify : (
>   	{ name = "swCompatibility"; value = "unknown";}
>   );
> 
> -#
> +#
>   # suricatta section: setup for backend
>   #
>   # Currently, they refer to the Hawkbit agent.
> @@ -176,6 +176,9 @@ identify : (
>   #			  Specify server connection timeout. If no connection has been established in this
>   #			  period, libcurl will consider connection unsuccessful.
>   #			  Default value is determined by underlying libcurl implementation (300s).
> +# max-download-speed : string
> +#			  Specify maximum download speed to use. Value can be expressed as
> +#			  B/s, kB/s, M/s, G/s. Example: 512k
> 
>   suricatta :
>   {
> @@ -192,6 +195,7 @@ suricatta :
>   	enable		= true;
>   	initial-report-resend-period = 30;
>   	connection-timeout = 10;
> +	max-download-speed = "1M";
>   /*
>   	cafile		= "/etc/ssl/cafile";
>   	sslkey		= "/etc/ssl/sslkey";
> diff --git a/include/channel_curl.h b/include/channel_curl.h
> index 6dabae6..8ecaf59 100644
> --- a/include/channel_curl.h
> +++ b/include/channel_curl.h
> @@ -74,4 +74,5 @@ typedef struct {
>   	sourcetype source;
>   	struct dict *headers_to_send;
>   	struct dict *received_headers;
> +	unsigned int max_download_speed;
>   } channel_data_t;
> diff --git a/suricatta/common.c b/suricatta/common.c
> index e5a3db2..71aa2df 100644
> --- a/suricatta/common.c
> +++ b/suricatta/common.c
> @@ -23,6 +23,10 @@ void suricatta_channel_settings(void *elem, channel_data_t *chan)
>   	get_field(LIBCFG_PARSER, elem, "retry",
>   		&chan->retries);
> 
> +	GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "max-download-speed", tmp);
> +	if (strlen(tmp))
> +		chan->max_download_speed = (unsigned int)ustrtoull(tmp, 10);
> +
>   	GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "retrywait", tmp);
>   	if (strlen(tmp))
>   		chan->retry_sleep =
> diff --git a/suricatta/server_general.c b/suricatta/server_general.c
> index d9ad50d..e8c3186 100644
> --- a/suricatta/server_general.c
> +++ b/suricatta/server_general.c
> @@ -65,6 +65,7 @@ static struct option long_options[] = {
>       {"retry", required_argument, NULL, 'r'},
>       {"retrywait", required_argument, NULL, 'w'},
>       {"cache", required_argument, NULL, '2'},
> +    {"max-download-speed", required_argument, NULL, 'n'},
>       {NULL, 0, NULL, 0}};
> 
>   static unsigned short mandatory_argument_count = 0;
> @@ -525,7 +526,9 @@ void server_print_help(void)
>   	    "\t  -y, --proxy         Use proxy. Either give proxy URL, else "
>   	    "{http,all}_proxy env is tried.\n"
>   	    "\t  -a, --custom-http-header <name> <value> Set custom HTTP header, "
> -	    "appended to every HTTP request being sent.",
> +	    "appended to every HTTP request being sent."
> +	    "\t  -n, --max-download-speed <limit>	Set download speed limit."
> +		"Example: -n 100k; -n 1M; -n 100; -n 1G",
>   	    CHANNEL_DEFAULT_POLLING_INTERVAL, CHANNEL_DEFAULT_RESUME_TRIES,
>   	    CHANNEL_DEFAULT_RESUME_DELAY);
>   }
> @@ -630,7 +633,7 @@ server_op_res_t server_start(char *fname, int argc, char *argv[])
>   	/* reset to optind=1 to parse suricatta's argument vector */
>   	optind = 1;
>   	opterr = 0;
> -	while ((choice = getopt_long(argc, argv, "u:l:r:w:p:2:a:",
> +	while ((choice = getopt_long(argc, argv, "u:l:r:w:p:2:a:n",
>   				     long_options, NULL)) != -1) {
>   		switch (choice) {
>   		case 'u':
> @@ -665,6 +668,11 @@ server_op_res_t server_start(char *fname, int argc, char *argv[])
>   				return SERVER_EINIT;
> 
>   			break;
> +		case 'n':
> +			channel_data_defaults.max_download_speed =
> +				(unsigned int)ustrtoull(optarg, 10);
> +			break;
> +
>   		case '?':
>   		/* Ignore not recognized options, they can be already parsed by the caller */
>   		default:
> diff --git a/suricatta/server_hawkbit.c b/suricatta/server_hawkbit.c
> index 9a338d8..f8f560e 100644
> --- a/suricatta/server_hawkbit.c
> +++ b/suricatta/server_hawkbit.c
> @@ -53,6 +53,7 @@ static struct option long_options[] = {
>       {"initial-report-resend-period", required_argument, NULL, 'm'},
>   	{"connection-timeout", required_argument, NULL, 's'},
>   	{"custom-http-header", required_argument, NULL, 'a'},
> +	{"max-download-speed", required_argument, NULL, 'l'},
>       {NULL, 0, NULL, 0}};
> 
>   static unsigned short mandatory_argument_count = 0;
> @@ -135,7 +136,8 @@ static channel_data_t channel_data_defaults = {.debug = false,
>   					       .strictssl = true,
>   						   .connection_timeout = 0,
>   						   .headers_to_send = NULL,
> -						   .received_headers = NULL
> +						   .received_headers = NULL,
> +						   .max_download_speed = 0 // No download speed limit is default.
>   						};
> 
>   static struct timeval server_time;
> @@ -1611,7 +1613,9 @@ void server_print_help(void)
>   	    "sending initial state with '-c' option (default: %ds).\n"
>   	    "\t  -s, --connection-timeout Set the server connection timeout (default: 300s).\n"
>   	    "\t  -a, --custom-http-header <name> <value> Set custom HTTP header, "
> -	    "appended to every HTTP request being sent.",
> +	    "appended to every HTTP request being sent.\n"
> +	    "\t  -n, --max-download-speed <limit>	Set download speed limit.\n"
> +		"Example: -n 100k; -n 1M; -n 100; -n 1G\n",
>   	    CHANNEL_DEFAULT_POLLING_INTERVAL, CHANNEL_DEFAULT_RESUME_TRIES,
>   	    CHANNEL_DEFAULT_RESUME_DELAY,
>   	    INITIAL_STATUS_REPORT_WAIT_DELAY);
> @@ -1702,7 +1706,7 @@ server_op_res_t server_start(char *fname, int argc, char *argv[])
>   	/* reset to optind=1 to parse suricatta's argument vector */
>   	optind = 1;
>   	opterr = 0;
> -	while ((choice = getopt_long(argc, argv, "t:i:c:u:p:xr:y::w:k:g:f:2:m:s:a:",
> +	while ((choice = getopt_long(argc, argv, "t:i:c:u:p:xr:y::w:k:g:f:2:m:s:a:n:",
>   				     long_options, NULL)) != -1) {
>   		switch (choice) {
>   		case 't':
> @@ -1803,7 +1807,10 @@ server_op_res_t server_start(char *fname, int argc, char *argv[])
>   						optarg,
>   						argv[optind++]) < 0)
>   				return SERVER_EINIT;
> -
> +			break;
> +		case 'n':
> +			channel_data_defaults.max_download_speed =
> +				(unsigned int)ustrtoull(optarg, 10);
>   			break;
>   		/* Ignore not recognized options, they can be already parsed by the caller */
>   		case '?':
> --
> 2.31.1
> 

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

Best regards,
Stefano Babic
Stefano Babic Oct. 5, 2021, 12:33 p.m. UTC | #2
On 24.09.21 15:49, Sava Jakovljev wrote:
> * Extend Suricatta and general server with options to set download speed
>    limit.
> * Add 'n' short and 'max-download-speed' long command line option for
>    setting download speed limit.
> * Add 'maximum-download-speed' option in configuration file.
> * Document new feature and provide configuration file example.
> 
> Signed-off-by: Sava Jakovljev <sava.jakovljev@teufel.de>


I supposed it was laready merged, it wasn't.

Applied to -master, thanks !

Best regards,
Stefano Babic
diff mbox series

Patch

diff --git a/corelib/channel_curl.c b/corelib/channel_curl.c
index 0761811..ff2053d 100644
--- a/corelib/channel_curl.c
+++ b/corelib/channel_curl.c
@@ -1104,6 +1104,15 @@  channel_op_res_t channel_get_file(channel_t *this, void *data)
 		goto cleanup_header;
 	}

+	if (channel_data->max_download_speed &&
+			curl_easy_setopt(channel_curl->handle,
+				CURLOPT_MAX_RECV_SPEED_LARGE,
+				channel_data->max_download_speed) != CURLE_OK) {
+		ERROR("Set channel download speed limit failed.");
+		result = CHANNEL_EINIT;
+		goto cleanup_header;
+	}
+
 	download_callback_data_t download_data;
 	if (channel_enable_download_progress_tracking(channel_curl,
 				channel_data->url,
diff --git a/corelib/downloader.c b/corelib/downloader.c
index 3d0a0a5..8596694 100644
--- a/corelib/downloader.c
+++ b/corelib/downloader.c
@@ -105,7 +105,8 @@  static channel_data_t channel_options = {
 	.debug = false,
 	.retries = DL_DEFAULT_RETRIES,
 	.low_speed_timeout = DL_LOWSPEED_TIME,
-	.headers_to_send = NULL
+	.headers_to_send = NULL,
+	.max_download_speed = 0 // Unlimited download speed is default.
 };

 int start_download(const char *fname, int argc, char *argv[])
diff --git a/doc/source/swupdate.rst b/doc/source/swupdate.rst
index 5af52f1..a81b87a 100644
--- a/doc/source/swupdate.rst
+++ b/doc/source/swupdate.rst
@@ -665,6 +665,14 @@  Mandatory arguments are marked with '\*':
 |                         |          | value to be sent with every HTTP request   |
 |                         |          | made.                                      |
 +-------------------------+----------+--------------------------------------------+
+| -n <value>              | string   | Maximum download speed to be used.         |
+|                         |          | Value be specified in kB/s, B/s, MB/s      |
+|                         |          | or GB/s. Examples:                         |
+|                         |          | -n 100k : Set limit to 100 kB/s.           |
+|                         |          | -n 500  : Set limit to 500 B/s.            |
+|                         |          | -n 2M   : Set limit to 1 M/s.              |
+|                         |          | -n 1G   : Set limit to 1 G/s.              |
++-------------------------+----------+--------------------------------------------+


 systemd Integration
diff --git a/examples/configuration/swupdate.cfg b/examples/configuration/swupdate.cfg
index 39a4401..ba36a31 100644
--- a/examples/configuration/swupdate.cfg
+++ b/examples/configuration/swupdate.cfg
@@ -18,7 +18,7 @@ 
 #	 		  enable sending logs to syslog daemon
 # public-key-file	: string
 #			  file with public key for
-#			  image verification
+#			  image verification
 # mtd-blacklist		: list integers
 #			  MTD devices where SWUpdate
 #			  must not try to check for UBI filesystem.
@@ -123,7 +123,7 @@  identify : (
 	{ name = "swCompatibility"; value = "unknown";}
 );

-#
+#
 # suricatta section: setup for backend
 #
 # Currently, they refer to the Hawkbit agent.
@@ -176,6 +176,9 @@  identify : (
 #			  Specify server connection timeout. If no connection has been established in this
 #			  period, libcurl will consider connection unsuccessful.
 #			  Default value is determined by underlying libcurl implementation (300s).
+# max-download-speed : string
+#			  Specify maximum download speed to use. Value can be expressed as
+#			  B/s, kB/s, M/s, G/s. Example: 512k

 suricatta :
 {
@@ -192,6 +195,7 @@  suricatta :
 	enable		= true;
 	initial-report-resend-period = 30;
 	connection-timeout = 10;
+	max-download-speed = "1M";
 /*
 	cafile		= "/etc/ssl/cafile";
 	sslkey		= "/etc/ssl/sslkey";
diff --git a/include/channel_curl.h b/include/channel_curl.h
index 6dabae6..8ecaf59 100644
--- a/include/channel_curl.h
+++ b/include/channel_curl.h
@@ -74,4 +74,5 @@  typedef struct {
 	sourcetype source;
 	struct dict *headers_to_send;
 	struct dict *received_headers;
+	unsigned int max_download_speed;
 } channel_data_t;
diff --git a/suricatta/common.c b/suricatta/common.c
index e5a3db2..71aa2df 100644
--- a/suricatta/common.c
+++ b/suricatta/common.c
@@ -23,6 +23,10 @@  void suricatta_channel_settings(void *elem, channel_data_t *chan)
 	get_field(LIBCFG_PARSER, elem, "retry",
 		&chan->retries);

+	GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "max-download-speed", tmp);
+	if (strlen(tmp))
+		chan->max_download_speed = (unsigned int)ustrtoull(tmp, 10);
+
 	GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "retrywait", tmp);
 	if (strlen(tmp))
 		chan->retry_sleep =
diff --git a/suricatta/server_general.c b/suricatta/server_general.c
index d9ad50d..e8c3186 100644
--- a/suricatta/server_general.c
+++ b/suricatta/server_general.c
@@ -65,6 +65,7 @@  static struct option long_options[] = {
     {"retry", required_argument, NULL, 'r'},
     {"retrywait", required_argument, NULL, 'w'},
     {"cache", required_argument, NULL, '2'},
+    {"max-download-speed", required_argument, NULL, 'n'},
     {NULL, 0, NULL, 0}};

 static unsigned short mandatory_argument_count = 0;
@@ -525,7 +526,9 @@  void server_print_help(void)
 	    "\t  -y, --proxy         Use proxy. Either give proxy URL, else "
 	    "{http,all}_proxy env is tried.\n"
 	    "\t  -a, --custom-http-header <name> <value> Set custom HTTP header, "
-	    "appended to every HTTP request being sent.",
+	    "appended to every HTTP request being sent."
+	    "\t  -n, --max-download-speed <limit>	Set download speed limit."
+		"Example: -n 100k; -n 1M; -n 100; -n 1G",
 	    CHANNEL_DEFAULT_POLLING_INTERVAL, CHANNEL_DEFAULT_RESUME_TRIES,
 	    CHANNEL_DEFAULT_RESUME_DELAY);
 }
@@ -630,7 +633,7 @@  server_op_res_t server_start(char *fname, int argc, char *argv[])
 	/* reset to optind=1 to parse suricatta's argument vector */
 	optind = 1;
 	opterr = 0;
-	while ((choice = getopt_long(argc, argv, "u:l:r:w:p:2:a:",
+	while ((choice = getopt_long(argc, argv, "u:l:r:w:p:2:a:n",
 				     long_options, NULL)) != -1) {
 		switch (choice) {
 		case 'u':
@@ -665,6 +668,11 @@  server_op_res_t server_start(char *fname, int argc, char *argv[])
 				return SERVER_EINIT;

 			break;
+		case 'n':
+			channel_data_defaults.max_download_speed =
+				(unsigned int)ustrtoull(optarg, 10);
+			break;
+
 		case '?':
 		/* Ignore not recognized options, they can be already parsed by the caller */
 		default:
diff --git a/suricatta/server_hawkbit.c b/suricatta/server_hawkbit.c
index 9a338d8..f8f560e 100644
--- a/suricatta/server_hawkbit.c
+++ b/suricatta/server_hawkbit.c
@@ -53,6 +53,7 @@  static struct option long_options[] = {
     {"initial-report-resend-period", required_argument, NULL, 'm'},
 	{"connection-timeout", required_argument, NULL, 's'},
 	{"custom-http-header", required_argument, NULL, 'a'},
+	{"max-download-speed", required_argument, NULL, 'l'},
     {NULL, 0, NULL, 0}};

 static unsigned short mandatory_argument_count = 0;
@@ -135,7 +136,8 @@  static channel_data_t channel_data_defaults = {.debug = false,
 					       .strictssl = true,
 						   .connection_timeout = 0,
 						   .headers_to_send = NULL,
-						   .received_headers = NULL
+						   .received_headers = NULL,
+						   .max_download_speed = 0 // No download speed limit is default.
 						};

 static struct timeval server_time;
@@ -1611,7 +1613,9 @@  void server_print_help(void)
 	    "sending initial state with '-c' option (default: %ds).\n"
 	    "\t  -s, --connection-timeout Set the server connection timeout (default: 300s).\n"
 	    "\t  -a, --custom-http-header <name> <value> Set custom HTTP header, "
-	    "appended to every HTTP request being sent.",
+	    "appended to every HTTP request being sent.\n"
+	    "\t  -n, --max-download-speed <limit>	Set download speed limit.\n"
+		"Example: -n 100k; -n 1M; -n 100; -n 1G\n",
 	    CHANNEL_DEFAULT_POLLING_INTERVAL, CHANNEL_DEFAULT_RESUME_TRIES,
 	    CHANNEL_DEFAULT_RESUME_DELAY,
 	    INITIAL_STATUS_REPORT_WAIT_DELAY);
@@ -1702,7 +1706,7 @@  server_op_res_t server_start(char *fname, int argc, char *argv[])
 	/* reset to optind=1 to parse suricatta's argument vector */
 	optind = 1;
 	opterr = 0;
-	while ((choice = getopt_long(argc, argv, "t:i:c:u:p:xr:y::w:k:g:f:2:m:s:a:",
+	while ((choice = getopt_long(argc, argv, "t:i:c:u:p:xr:y::w:k:g:f:2:m:s:a:n:",
 				     long_options, NULL)) != -1) {
 		switch (choice) {
 		case 't':
@@ -1803,7 +1807,10 @@  server_op_res_t server_start(char *fname, int argc, char *argv[])
 						optarg,
 						argv[optind++]) < 0)
 				return SERVER_EINIT;
-
+			break;
+		case 'n':
+			channel_data_defaults.max_download_speed =
+				(unsigned int)ustrtoull(optarg, 10);
 			break;
 		/* Ignore not recognized options, they can be already parsed by the caller */
 		case '?':