aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoriddq <iddq>2025-07-26 14:00:56 +0200
committerMarton Balint <cus@passwd.hu>2025-08-22 18:20:08 +0000
commit4e9a184d5c948ce89fc7cd0954c9e1600e776db9 (patch)
tree4160c62f73323bf09a6c9f04d0769596605b96c4
parentf62d8789116fef8d8cd7f20062b16ccd93f7ce23 (diff)
downloadffmpeg-4e9a184d5c948ce89fc7cd0954c9e1600e776db9.tar.gz
avformat/tcp: add option for enabling TCP keepalive
-rw-r--r--doc/protocols.texi5
-rw-r--r--libavformat/tcp.c11
2 files changed, 16 insertions, 0 deletions
diff --git a/doc/protocols.texi b/doc/protocols.texi
index fa2df39a1d..6b582fde30 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -986,6 +986,11 @@ Set TCP_NODELAY to disable Nagle's algorithm. Default value is 0.
@emph{Remark: Writing to the socket is currently not optimized to minimize system calls and reduces the efficiency / effect of TCP_NODELAY.}
+@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.
+
@end table
For example to read with @command{ffplay} a multimedia resource named
diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index 755e3af242..c286698d33 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -44,6 +44,7 @@ typedef struct TCPContext {
int recv_buffer_size;
int send_buffer_size;
int tcp_nodelay;
+ int tcp_keepalive;
#if !HAVE_WINSOCK2_H
int tcp_mss;
#endif /* !HAVE_WINSOCK2_H */
@@ -61,6 +62,7 @@ static const AVOption options[] = {
{ "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "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 },
#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 */
@@ -125,6 +127,12 @@ static int customize_fd(void *ctx, int fd, int family)
ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_NODELAY)");
}
}
+ if (s->tcp_keepalive > 0) {
+ 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)");
+ }
+ }
+
#if !HAVE_WINSOCK2_H
if (s->tcp_mss > 0) {
if (setsockopt (fd, IPPROTO_TCP, TCP_MAXSEG, &s->tcp_mss, sizeof (s->tcp_mss))) {
@@ -187,6 +195,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
if (av_find_info_tag(buf, sizeof(buf), "tcp_nodelay", p)) {
s->tcp_nodelay = strtol(buf, NULL, 10);
}
+ if (av_find_info_tag(buf, sizeof(buf), "tcp_keepalive", p)) {
+ s->tcp_keepalive = strtol(buf, NULL, 10);
+ }
}
if (s->rw_timeout >= 0) {
s->open_timeout =