diff --git a/doc/xml/release.xml b/doc/xml/release.xml index 5b48867e8..75ecfaac6 100644 --- a/doc/xml/release.xml +++ b/doc/xml/release.xml @@ -45,6 +45,14 @@ + + + + + +

Set TCP keepalives on S3 connections.

+
+ diff --git a/lib/pgBackRest/Common/Http/Client.pm b/lib/pgBackRest/Common/Http/Client.pm index c2c939f06..2cb04654a 100644 --- a/lib/pgBackRest/Common/Http/Client.pm +++ b/lib/pgBackRest/Common/Http/Client.pm @@ -12,6 +12,7 @@ use English '-no_match_vars'; use Exporter qw(import); our @EXPORT = qw(); use IO::Socket::SSL; +use Socket qw(SOL_SOCKET SO_KEEPALIVE); use pgBackRest::Common::Exception; use pgBackRest::Common::Io::Buffered; @@ -100,7 +101,7 @@ sub new { $oSocket = IO::Socket::SSL->new( PeerHost => $strHost, PeerPort => $iPort, SSL_verify_mode => $bVerifySsl ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, - SSL_ca_path => $strCaPath, SSL_ca_file => $strCaFile); + SSL_ca_path => $strCaPath, SSL_ca_file => $strCaFile, Sockopts => [[SOL_SOCKET, SO_KEEPALIVE]]); return 1; } diff --git a/src/common/io/tls/client.c b/src/common/io/tls/client.c index e688f2ad3..321f6314c 100644 --- a/src/common/io/tls/client.c +++ b/src/common/io/tls/client.c @@ -307,6 +307,32 @@ tlsClientOpen(TlsClient *this) if (connect(this->socket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) == -1) THROW_SYS_ERROR_FMT(FileOpenError, "unable to connect to '%s:%u'", strPtr(this->host), this->port); + // Enable TCP keepalives + int socketValue = 1; + + THROW_ON_SYS_ERROR( + setsockopt(this->socket, SOL_SOCKET, SO_KEEPALIVE, &socketValue, sizeof(int)) == -1, ProtocolError, + "unable set SO_KEEPALIVE"); + + // Set per-connection keepalive options if they are available +#ifdef TCP_KEEPIDLE + socketValue = 3; + + THROW_ON_SYS_ERROR( + setsockopt(this->socket, SOL_SOCKET, TCP_KEEPIDLE, &socketValue, sizeof(int)) == -1, ProtocolError, + "unable set SO_KEEPIDLE"); + + THROW_ON_SYS_ERROR( + setsockopt(this->socket, SOL_SOCKET, TCP_KEEPINTVL, &socketValue, sizeof(int)) == -1, ProtocolError, + "unable set SO_KEEPINTVL"); + + socketValue = this->timeout / socketValue; + + THROW_ON_SYS_ERROR( + setsockopt(this->socket, SOL_SOCKET, TCP_KEEPCNT, &socketValue, sizeof(int)) == -1, ProtocolError, + "unable set SO_KEEPCNT"); +#endif + // Negotiate TLS cryptoError((this->session = SSL_new(this->context)) == NULL, "unable to create TLS context"); diff --git a/src/perl/embed.auto.c b/src/perl/embed.auto.c index d24f77ba5..8ae79eefe 100644 --- a/src/perl/embed.auto.c +++ b/src/perl/embed.auto.c @@ -5253,6 +5253,7 @@ static const EmbeddedModule embeddedModule[] = "use Exporter qw(import);\n" "our @EXPORT = qw();\n" "use IO::Socket::SSL;\n" + "use Socket qw(SOL_SOCKET SO_KEEPALIVE);\n" "\n" "use pgBackRest::Common::Exception;\n" "use pgBackRest::Common::Io::Buffered;\n" @@ -5333,7 +5334,7 @@ static const EmbeddedModule embeddedModule[] = "{\n" "$oSocket = IO::Socket::SSL->new(\n" "PeerHost => $strHost, PeerPort => $iPort, SSL_verify_mode => $bVerifySsl ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,\n" - "SSL_ca_path => $strCaPath, SSL_ca_file => $strCaFile);\n" + "SSL_ca_path => $strCaPath, SSL_ca_file => $strCaFile, Sockopts => [[SOL_SOCKET, SO_KEEPALIVE]]);\n" "\n" "return 1;\n" "}\n"