* [FFmpeg-devel] [PATCH] tcp: add TCP keepalive tuning options
@ 2025-11-20 22:25 Practice2001 via ffmpeg-devel
2025-11-24 13:22 ` [FFmpeg-devel] " Nicolas George via ffmpeg-devel
0 siblings, 1 reply; 3+ messages in thread
From: Practice2001 via ffmpeg-devel @ 2025-11-20 22:25 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Practice2001
Addition of tcp_keepalive, tcp_keepidle, tcp_keepintvl, and tcp_keepcnt
support to the TCP protocol. Exposeing these options to the HTTP protocol
so they can be used for HTTP(S) connections. Updated documentation.
Tested with: ./configure && make && make fate
Fixes ticket #11671.
Signed-off-by: Practice2001 <cordacct2001@gmail.com>
---
doc/protocols.texi | 26 ++++++++++++++-
libavformat/http.c | 36 +++++++++++++++++++++
libavformat/tcp.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 141 insertions(+), 1 deletion(-)
diff --git a/doc/protocols.texi b/doc/protocols.texi
index b74383122a..848f4820e2 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -989,7 +989,31 @@ Set TCP_NODELAY to disable Nagle's algorithm. Default value is 0.
@item tcp_keepalive=@var{1|0}
Enable the TCP keepalive mechanism to detect dead peers and help maintain long-lived idle connections. Default value is 0.
-Only the basic keepalive option (SO_KEEPALIVE) can be enabled or disabled. Platform-specific tuning parameters such as TCP_KEEPIDLE, TCP_KEEPINTVL, or TCP_KEEPCNT are not configurable and will use the operating system's default values.
+The basic keepalive option (SO_KEEPALIVE) can be enabled or disabled. Platform-specific tuning parameters such as TCP_KEEPIDLE, TCP_KEEPINTVL, or TCP_KEEPCNT are configurable.
+
+@item tcp_keepidle=@var{seconds}
+Set the TCP keepalive idle time (in seconds).
+
+This controls how long the connection must remain idle before the first
+keepalive probe is sent.
+
+Default is 0 (uses system default).
+
+@item tcp_keepintvl=@var{seconds}
+Set the interval (in seconds) between individual TCP keepalive probes.
+
+Default is 0 (uses system default).
+
+@item tcp_keepcnt=@var{count}
+Set the number of unacknowledged keepalive probes that must occur before
+the connection is considered dead.
+
+Default is 0 (uses system default).
+
+@emph{Note:}
+These platform-specific parameters are available on Linux and BSD-derived
+systems. On Windows, only basic keepalive configuration is supported and
+the underlying system will use its own values for probe timing and count.
@end table
diff --git a/libavformat/http.c b/libavformat/http.c
index c4e6292a95..1c264d845c 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -146,6 +146,11 @@ typedef struct HTTPContext {
unsigned int retry_after;
int reconnect_max_retries;
int reconnect_delay_total_max;
+ /* TCP keepalive forwarding */
+ int tcp_keepalive; /* -1 = unset, 0 = off, 1 = on */
+ int tcp_keepidle; /* seconds, 0 = unset */
+ int tcp_keepintvl; /* seconds, 0 = unset */
+ int tcp_keepcnt; /* probe count, 0 = unset */
} HTTPContext;
#define OFFSET(x) offsetof(HTTPContext, x)
@@ -191,6 +196,10 @@ static const AVOption options[] = {
{ "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
{ "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E},
{ "short_seek_size", "Threshold to favor readahead over seek.", OFFSET(short_seek_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D },
+ { "tcp_keepalive", "Enable SO_KEEPALIVE on underlying TCP socket", OFFSET(tcp_keepalive), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, D | E },
+ { "tcp_keepidle", "TCP keepalive idle time (seconds) for underlying TCP socket", OFFSET(tcp_keepidle), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D | E },
+ { "tcp_keepintvl", "TCP keepalive interval (seconds) for underlying TCP socket", OFFSET(tcp_keepintvl), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D | E },
+ { "tcp_keepcnt", "TCP keepalive probe count for underlying TCP socket", OFFSET(tcp_keepcnt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D | E },
{ NULL }
};
@@ -282,6 +291,33 @@ static int http_open_cnx_internal(URLContext *h, AVDictionary **options)
ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
+
+ /* Forward TCP keepalive options to underlying protocol via options dict.
+ * Prefer using AVDictionary forwarding to modifying the URL (safer). */
+ if (options) {
+ int err = 0;
+ if (s->tcp_keepalive != -1) {
+ err = av_dict_set_int(options, "tcp_keepalive", s->tcp_keepalive ? 1 : 0, 0);
+ if (err < 0)
+ goto end; /* existing cleanup label in this function */
+ }
+ if (s->tcp_keepidle > 0) {
+ err = av_dict_set_int(options, "tcp_keepidle", s->tcp_keepidle, 0);
+ if (err < 0)
+ goto end;
+ }
+ if (s->tcp_keepintvl > 0) {
+ err = av_dict_set_int(options, "tcp_keepintvl", s->tcp_keepintvl, 0);
+ if (err < 0)
+ goto end;
+ }
+ if (s->tcp_keepcnt > 0) {
+ err = av_dict_set_int(options, "tcp_keepcnt", s->tcp_keepcnt, 0);
+ if (err < 0)
+ goto end;
+ }
+ }
+
if (!s->hd) {
err = ffurl_open_whitelist(&s->hd, buf, AVIO_FLAG_READ_WRITE,
&h->interrupt_callback, options,
diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index ce9f69a50b..eb3dd0cc5b 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -46,6 +46,9 @@ typedef struct TCPContext {
int send_buffer_size;
int tcp_nodelay;
int tcp_keepalive;
+ int tcp_keepidle;
+ int tcp_keepintvl;
+ int tcp_keepcnt;
#if !HAVE_WINSOCK2_H
int tcp_mss;
#endif /* !HAVE_WINSOCK2_H */
@@ -54,6 +57,28 @@ typedef struct TCPContext {
#define OFFSET(x) offsetof(TCPContext, x)
#define D AV_OPT_FLAG_DECODING_PARAM
#define E AV_OPT_FLAG_ENCODING_PARAM
+
+/**
+ * @name TCP keepalive tuning options
+ *
+ * These AVOptions extend TCP keepalive controls beyond the basic SO_KEEPALIVE
+ * flag by exposing platform-supported tuning parameters.
+ *
+ * The following options may be set on the "tcp" protocol:
+ *
+ * - @ref tcp_keepalive : Enable or disable SO_KEEPALIVE.
+ * - @ref tcp_keepidle : Set idle time (seconds) before sending first probe.
+ * - @ref tcp_keepintvl : Set interval (seconds) between keepalive probes.
+ * - @ref tcp_keepcnt : Set number of failed probes before declaring dead.
+ *
+ * Notes:
+ * - Linux and BSD systems expose all parameters.
+ * - Windows only supports enabling keepalive; tuning values are ignored.
+ *
+ * These options improve robustness of long-lived idle connections and help
+ * detect dead peers sooner than system defaults.
+ */
+
static const AVOption options[] = {
{ "listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, .flags = D|E },
{ "local_port", "Local port", OFFSET(local_port), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, .flags = D|E },
@@ -64,6 +89,9 @@ static const AVOption options[] = {
{ "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "tcp_nodelay", "Use TCP_NODELAY to disable nagle's algorithm", OFFSET(tcp_nodelay), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = D|E },
{ "tcp_keepalive", "Use TCP keepalive to detect dead connections and keep long-lived connections active.", OFFSET(tcp_keepalive), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = D|E },
+ { "tcp_keepidle", "TCP keepalive idle time in seconds", OFFSET(tcp_keepidle), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = D|E },
+ { "tcp_keepintvl", "TCP keepalive probe interval in seconds", OFFSET(tcp_keepintvl), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = D|E },
+ { "tcp_keepcnt", "TCP keepalive probe count", OFFSET(tcp_keepcnt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = D|E },
#if !HAVE_WINSOCK2_H
{ "tcp_mss", "Maximum segment size for outgoing TCP packets", OFFSET(tcp_mss), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
#endif /* !HAVE_WINSOCK2_H */
@@ -132,6 +160,58 @@ static int customize_fd(void *ctx, int fd, int family)
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &s->tcp_keepalive, sizeof(s->tcp_keepalive))) {
ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(SO_KEEPALIVE)");
}
+ /* Attempt to set keepalive tuning if requested */
+ /* POSIX/Linux/BSD style */
+ #if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE)
+ if (s->tcp_keepidle > 0) {
+# ifdef TCP_KEEPIDLE
+ int idle = s->tcp_keepidle;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) {
+ ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_KEEPIDLE)");
+ }
+# elif defined(TCP_KEEPALIVE)
+ int idle = s->tcp_keepidle;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &idle, sizeof(idle))) {
+ ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_KEEPALIVE)");
+ }
+# endif
+ }
+ if (s->tcp_keepintvl > 0) {
+# ifdef TCP_KEEPINTVL
+ int kv = s->tcp_keepintvl;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &kv, sizeof(kv))) {
+ ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_KEEPINTVL)");
+ }
+# endif
+ }
+ if (s->tcp_keepcnt > 0) {
+# ifdef TCP_KEEPCNT
+ int kc = s->tcp_keepcnt;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &kc, sizeof(kc))) {
+ ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_KEEPCNT)");
+ }
+# endif
+ }
+ #endif /* defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE) */
+
+ /* Windows SIO_KEEPALIVE_VALS via WSAIoctl */
+ #if HAVE_WINSOCK2_H
+ if (s->tcp_keepidle > 0 || s->tcp_keepintvl > 0) {
+# include <mstcpip.h>
+ /* windows expects milliseconds */
+ struct tcp_keepalive vals;
+ DWORD bytes;
+ vals.onoff = 1;
+ vals.keepalivetime = (DWORD)(s->tcp_keepidle > 0 ? (DWORD)s->tcp_keepidle * 1000 : 7200000);
+ vals.keepaliveinterval = (DWORD)(s->tcp_keepintvl > 0 ? (DWORD)s->tcp_keepintvl * 1000 : 1000);
+ /* WSAIoctl returns SOCKET_ERROR on failure */
+ if (WSAIoctl((SOCKET)fd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals),
+ NULL, 0, &bytes, NULL, NULL) == SOCKET_ERROR) {
+ ff_log_net_error(ctx, AV_LOG_WARNING, "WSAIoctl(SIO_KEEPALIVE_VALS)");
+ }
+ }
+ #endif /* HAVE_WINSOCK2_H */
+
}
#if !HAVE_WINSOCK2_H
--
2.34.1
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] 3+ messages in thread
* [FFmpeg-devel] Re: [PATCH] tcp: add TCP keepalive tuning options
2025-11-20 22:25 [FFmpeg-devel] [PATCH] tcp: add TCP keepalive tuning options Practice2001 via ffmpeg-devel
@ 2025-11-24 13:22 ` Nicolas George via ffmpeg-devel
0 siblings, 0 replies; 3+ messages in thread
From: Nicolas George via ffmpeg-devel @ 2025-11-24 13:22 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Practice2001, Nicolas George
Practice2001 via ffmpeg-devel (HE12025-11-21):
> Addition of tcp_keepalive, tcp_keepidle, tcp_keepintvl, and tcp_keepcnt
> support to the TCP protocol. Exposeing these options to the HTTP protocol
> so they can be used for HTTP(S) connections. Updated documentation.
> Tested with: ./configure && make && make fate
>
> Fixes ticket #11671.
>
> Signed-off-by: Practice2001 <cordacct2001@gmail.com>
> ---
> doc/protocols.texi | 26 ++++++++++++++-
> libavformat/http.c | 36 +++++++++++++++++++++
> libavformat/tcp.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 141 insertions(+), 1 deletion(-)
Hi.
Is there something new in this proposal that makes my comment of a few
days ago
<https://lists.ffmpeg.org/lore/ffmpeg-devel/aSCqAx-_6RFXR8Wq@phare.normalesup.org/>
obsolete?
If your goal is to fix broken connections that take forever to be
recognized as broken, you need to implement it as application logic, you
cannot rely on kernel parameters not meant for that, especially kernel
parameters that do not exist on some supported systems. At the very
least your solution needs to work on Windows.
Regards,
--
Nicolas George
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] 3+ messages in thread
* [FFmpeg-devel] [PATCH] tcp: add TCP keepalive tuning options
@ 2025-11-21 17:45 Practice2001 via ffmpeg-devel
0 siblings, 0 replies; 3+ messages in thread
From: Practice2001 via ffmpeg-devel @ 2025-11-21 17:45 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Practice2001
Addition of tcp_keepalive, tcp_keepidle, tcp_keepintvl, and tcp_keepcnt
support to the TCP protocol. Exposeing these options to the HTTP protocol
so they can be used for HTTP(S) connections. Updated documentation.
Tested with: ./configure && make && make fate
Fixes ticket #11671.
Signed-off-by: Practice2001 <cordacct2001@gmail.com>
---
doc/protocols.texi | 26 ++++++++++++++-
libavformat/http.c | 36 +++++++++++++++++++++
libavformat/tcp.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 141 insertions(+), 1 deletion(-)
diff --git a/doc/protocols.texi b/doc/protocols.texi
index b74383122a..848f4820e2 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -989,7 +989,31 @@ Set TCP_NODELAY to disable Nagle's algorithm. Default value is 0.
@item tcp_keepalive=@var{1|0}
Enable the TCP keepalive mechanism to detect dead peers and help maintain long-lived idle connections. Default value is 0.
-Only the basic keepalive option (SO_KEEPALIVE) can be enabled or disabled. Platform-specific tuning parameters such as TCP_KEEPIDLE, TCP_KEEPINTVL, or TCP_KEEPCNT are not configurable and will use the operating system's default values.
+The basic keepalive option (SO_KEEPALIVE) can be enabled or disabled. Platform-specific tuning parameters such as TCP_KEEPIDLE, TCP_KEEPINTVL, or TCP_KEEPCNT are configurable.
+
+@item tcp_keepidle=@var{seconds}
+Set the TCP keepalive idle time (in seconds).
+
+This controls how long the connection must remain idle before the first
+keepalive probe is sent.
+
+Default is 0 (uses system default).
+
+@item tcp_keepintvl=@var{seconds}
+Set the interval (in seconds) between individual TCP keepalive probes.
+
+Default is 0 (uses system default).
+
+@item tcp_keepcnt=@var{count}
+Set the number of unacknowledged keepalive probes that must occur before
+the connection is considered dead.
+
+Default is 0 (uses system default).
+
+@emph{Note:}
+These platform-specific parameters are available on Linux and BSD-derived
+systems. On Windows, only basic keepalive configuration is supported and
+the underlying system will use its own values for probe timing and count.
@end table
diff --git a/libavformat/http.c b/libavformat/http.c
index c4e6292a95..1c264d845c 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -146,6 +146,11 @@ typedef struct HTTPContext {
unsigned int retry_after;
int reconnect_max_retries;
int reconnect_delay_total_max;
+ /* TCP keepalive forwarding */
+ int tcp_keepalive; /* -1 = unset, 0 = off, 1 = on */
+ int tcp_keepidle; /* seconds, 0 = unset */
+ int tcp_keepintvl; /* seconds, 0 = unset */
+ int tcp_keepcnt; /* probe count, 0 = unset */
} HTTPContext;
#define OFFSET(x) offsetof(HTTPContext, x)
@@ -191,6 +196,10 @@ static const AVOption options[] = {
{ "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
{ "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E},
{ "short_seek_size", "Threshold to favor readahead over seek.", OFFSET(short_seek_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D },
+ { "tcp_keepalive", "Enable SO_KEEPALIVE on underlying TCP socket", OFFSET(tcp_keepalive), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, D | E },
+ { "tcp_keepidle", "TCP keepalive idle time (seconds) for underlying TCP socket", OFFSET(tcp_keepidle), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D | E },
+ { "tcp_keepintvl", "TCP keepalive interval (seconds) for underlying TCP socket", OFFSET(tcp_keepintvl), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D | E },
+ { "tcp_keepcnt", "TCP keepalive probe count for underlying TCP socket", OFFSET(tcp_keepcnt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D | E },
{ NULL }
};
@@ -282,6 +291,33 @@ static int http_open_cnx_internal(URLContext *h, AVDictionary **options)
ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
+
+ /* Forward TCP keepalive options to underlying protocol via options dict.
+ * Prefer using AVDictionary forwarding to modifying the URL (safer). */
+ if (options) {
+ int err = 0;
+ if (s->tcp_keepalive != -1) {
+ err = av_dict_set_int(options, "tcp_keepalive", s->tcp_keepalive ? 1 : 0, 0);
+ if (err < 0)
+ goto end; /* existing cleanup label in this function */
+ }
+ if (s->tcp_keepidle > 0) {
+ err = av_dict_set_int(options, "tcp_keepidle", s->tcp_keepidle, 0);
+ if (err < 0)
+ goto end;
+ }
+ if (s->tcp_keepintvl > 0) {
+ err = av_dict_set_int(options, "tcp_keepintvl", s->tcp_keepintvl, 0);
+ if (err < 0)
+ goto end;
+ }
+ if (s->tcp_keepcnt > 0) {
+ err = av_dict_set_int(options, "tcp_keepcnt", s->tcp_keepcnt, 0);
+ if (err < 0)
+ goto end;
+ }
+ }
+
if (!s->hd) {
err = ffurl_open_whitelist(&s->hd, buf, AVIO_FLAG_READ_WRITE,
&h->interrupt_callback, options,
diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index ce9f69a50b..eb3dd0cc5b 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -46,6 +46,9 @@ typedef struct TCPContext {
int send_buffer_size;
int tcp_nodelay;
int tcp_keepalive;
+ int tcp_keepidle;
+ int tcp_keepintvl;
+ int tcp_keepcnt;
#if !HAVE_WINSOCK2_H
int tcp_mss;
#endif /* !HAVE_WINSOCK2_H */
@@ -54,6 +57,28 @@ typedef struct TCPContext {
#define OFFSET(x) offsetof(TCPContext, x)
#define D AV_OPT_FLAG_DECODING_PARAM
#define E AV_OPT_FLAG_ENCODING_PARAM
+
+/**
+ * @name TCP keepalive tuning options
+ *
+ * These AVOptions extend TCP keepalive controls beyond the basic SO_KEEPALIVE
+ * flag by exposing platform-supported tuning parameters.
+ *
+ * The following options may be set on the "tcp" protocol:
+ *
+ * - @ref tcp_keepalive : Enable or disable SO_KEEPALIVE.
+ * - @ref tcp_keepidle : Set idle time (seconds) before sending first probe.
+ * - @ref tcp_keepintvl : Set interval (seconds) between keepalive probes.
+ * - @ref tcp_keepcnt : Set number of failed probes before declaring dead.
+ *
+ * Notes:
+ * - Linux and BSD systems expose all parameters.
+ * - Windows only supports enabling keepalive; tuning values are ignored.
+ *
+ * These options improve robustness of long-lived idle connections and help
+ * detect dead peers sooner than system defaults.
+ */
+
static const AVOption options[] = {
{ "listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, .flags = D|E },
{ "local_port", "Local port", OFFSET(local_port), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, .flags = D|E },
@@ -64,6 +89,9 @@ static const AVOption options[] = {
{ "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "tcp_nodelay", "Use TCP_NODELAY to disable nagle's algorithm", OFFSET(tcp_nodelay), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = D|E },
{ "tcp_keepalive", "Use TCP keepalive to detect dead connections and keep long-lived connections active.", OFFSET(tcp_keepalive), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = D|E },
+ { "tcp_keepidle", "TCP keepalive idle time in seconds", OFFSET(tcp_keepidle), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = D|E },
+ { "tcp_keepintvl", "TCP keepalive probe interval in seconds", OFFSET(tcp_keepintvl), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = D|E },
+ { "tcp_keepcnt", "TCP keepalive probe count", OFFSET(tcp_keepcnt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = D|E },
#if !HAVE_WINSOCK2_H
{ "tcp_mss", "Maximum segment size for outgoing TCP packets", OFFSET(tcp_mss), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
#endif /* !HAVE_WINSOCK2_H */
@@ -132,6 +160,58 @@ static int customize_fd(void *ctx, int fd, int family)
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &s->tcp_keepalive, sizeof(s->tcp_keepalive))) {
ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(SO_KEEPALIVE)");
}
+ /* Attempt to set keepalive tuning if requested */
+ /* POSIX/Linux/BSD style */
+ #if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE)
+ if (s->tcp_keepidle > 0) {
+# ifdef TCP_KEEPIDLE
+ int idle = s->tcp_keepidle;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) {
+ ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_KEEPIDLE)");
+ }
+# elif defined(TCP_KEEPALIVE)
+ int idle = s->tcp_keepidle;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &idle, sizeof(idle))) {
+ ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_KEEPALIVE)");
+ }
+# endif
+ }
+ if (s->tcp_keepintvl > 0) {
+# ifdef TCP_KEEPINTVL
+ int kv = s->tcp_keepintvl;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &kv, sizeof(kv))) {
+ ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_KEEPINTVL)");
+ }
+# endif
+ }
+ if (s->tcp_keepcnt > 0) {
+# ifdef TCP_KEEPCNT
+ int kc = s->tcp_keepcnt;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &kc, sizeof(kc))) {
+ ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_KEEPCNT)");
+ }
+# endif
+ }
+ #endif /* defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE) */
+
+ /* Windows SIO_KEEPALIVE_VALS via WSAIoctl */
+ #if HAVE_WINSOCK2_H
+ if (s->tcp_keepidle > 0 || s->tcp_keepintvl > 0) {
+# include <mstcpip.h>
+ /* windows expects milliseconds */
+ struct tcp_keepalive vals;
+ DWORD bytes;
+ vals.onoff = 1;
+ vals.keepalivetime = (DWORD)(s->tcp_keepidle > 0 ? (DWORD)s->tcp_keepidle * 1000 : 7200000);
+ vals.keepaliveinterval = (DWORD)(s->tcp_keepintvl > 0 ? (DWORD)s->tcp_keepintvl * 1000 : 1000);
+ /* WSAIoctl returns SOCKET_ERROR on failure */
+ if (WSAIoctl((SOCKET)fd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals),
+ NULL, 0, &bytes, NULL, NULL) == SOCKET_ERROR) {
+ ff_log_net_error(ctx, AV_LOG_WARNING, "WSAIoctl(SIO_KEEPALIVE_VALS)");
+ }
+ }
+ #endif /* HAVE_WINSOCK2_H */
+
}
#if !HAVE_WINSOCK2_H
--
2.34.1
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-11-24 13:22 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-11-20 22:25 [FFmpeg-devel] [PATCH] tcp: add TCP keepalive tuning options Practice2001 via ffmpeg-devel
2025-11-24 13:22 ` [FFmpeg-devel] " Nicolas George via ffmpeg-devel
2025-11-21 17:45 [FFmpeg-devel] " Practice2001 via ffmpeg-devel
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git