diff mbox series

[FFmpeg-devel,v2,7/9] avformat/http: Add option to limit total reconnect delay

Message ID 20240422142547.281064-8-derek.buitenhuis@gmail.com
State New
Headers show
Series HTTP rate limiting and retry improvements | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Derek Buitenhuis April 22, 2024, 2:25 p.m. UTC
The existing option only allows users to set the max delay for a
single attempt, rather than the total allowed delay, which is both
pretty unintitive, and only applicable when exponential backoff is
used.

The default for this option is set to 256, which is just above the
effective total delay accomplished by the the existing
reconnect_delay_max default of 120.

Signed-off-by: Derek Buitenhuis <derek.buitenhuis@gmail.com>
---
 libavformat/http.c    | 12 ++++++++++--
 libavformat/version.h |  2 +-
 2 files changed, 11 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/libavformat/http.c b/libavformat/http.c
index 06bd3e340e..930c115ec3 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -141,6 +141,7 @@  typedef struct HTTPContext {
     int respect_retry_after;
     unsigned int retry_after;
     int reconnect_max_retries;
+    int reconnect_delay_total_max;
 } HTTPContext;
 
 #define OFFSET(x) offsetof(HTTPContext, x)
@@ -180,6 +181,7 @@  static const AVOption options[] = {
     { "reconnect_streamed", "auto reconnect streamed / non seekable streams", OFFSET(reconnect_streamed), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
     { "reconnect_delay_max", "max reconnect delay in seconds after which to give up", OFFSET(reconnect_delay_max), AV_OPT_TYPE_INT, { .i64 = 120 }, 0, UINT_MAX/1000/1000, D },
     { "reconnect_max_retries", "the max number of times to retry a connection", OFFSET(reconnect_max_retries), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, D },
+    { "reconnect_delay_total_max", "max total reconnect delay in seconds after which to give up", OFFSET(reconnect_delay_total_max), AV_OPT_TYPE_INT, { .i64 = 256 }, 0, UINT_MAX/1000/1000, D },
     { "respect_retry_after", "respect the Retry-After header when retrying connections", OFFSET(respect_retry_after), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D },
     { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E },
     { "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
@@ -363,6 +365,7 @@  static int http_open_cnx(URLContext *h, AVDictionary **options)
     HTTPContext *s = h->priv_data;
     int ret, conn_attempts = 1, auth_attempts = 0, redirects = 0;
     int reconnect_delay = 0;
+    int reconnect_delay_total = 0;
     uint64_t off;
     char *cached;
 
@@ -389,7 +392,8 @@  redo:
     if (ret < 0) {
         if (!http_should_reconnect(s, ret) ||
             reconnect_delay > s->reconnect_delay_max ||
-            (s->reconnect_max_retries >= 0 && conn_attempts > s->reconnect_max_retries))
+            (s->reconnect_max_retries >= 0 && conn_attempts > s->reconnect_max_retries) ||
+            reconnect_delay_total > s->reconnect_delay_total_max)
             goto fail;
 
         if (s->respect_retry_after && s->retry_after > 0) {
@@ -403,6 +407,7 @@  redo:
         ret = ff_network_sleep_interruptible(1000U * 1000 * reconnect_delay, &h->interrupt_callback);
         if (ret != AVERROR(ETIMEDOUT))
             goto fail;
+        reconnect_delay_total += reconnect_delay;
         reconnect_delay = 1 + 2 * reconnect_delay;
         conn_attempts++;
 
@@ -1710,6 +1715,7 @@  static int http_read_stream(URLContext *h, uint8_t *buf, int size)
     int err, read_ret;
     int64_t seek_ret;
     int reconnect_delay = 0;
+    int reconnect_delay_total = 0;
     int conn_attempt = 1;
 
     if (!s->hd)
@@ -1739,13 +1745,15 @@  static int http_read_stream(URLContext *h, uint8_t *buf, int size)
             !(s->reconnect_at_eof && read_ret == AVERROR_EOF))
             break;
 
-        if (reconnect_delay > s->reconnect_delay_max || (s->reconnect_max_retries >= 0 && conn_attempt > s->reconnect_max_retries))
+        if (reconnect_delay > s->reconnect_delay_max || (s->reconnect_max_retries >= 0 && conn_attempt > s->reconnect_max_retries) ||
+            reconnect_delay_total > s->reconnect_delay_total_max)
             return AVERROR(EIO);
 
         av_log(h, AV_LOG_WARNING, "Will reconnect at %"PRIu64" in %d second(s), error=%s.\n", s->off, reconnect_delay, av_err2str(read_ret));
         err = ff_network_sleep_interruptible(1000U*1000*reconnect_delay, &h->interrupt_callback);
         if (err != AVERROR(ETIMEDOUT))
             return err;
+        reconnect_delay_total += reconnect_delay;
         reconnect_delay = 1 + 2*reconnect_delay;
         conn_attempt++;
         seek_ret = http_seek_internal(h, target, SEEK_SET, 1);
diff --git a/libavformat/version.h b/libavformat/version.h
index 41dbd4ad01..5310326bda 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -32,7 +32,7 @@ 
 #include "version_major.h"
 
 #define LIBAVFORMAT_VERSION_MINOR   3
-#define LIBAVFORMAT_VERSION_MICRO 102
+#define LIBAVFORMAT_VERSION_MICRO 103
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \