This is an automated email from the ASF dual-hosted git repository. swebb2066 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git
The following commit(s) were added to refs/heads/master by this push: new 9659f082 Ensure messages are delivered by TelnetAppender when the socket is in a TIME_WAIT state (#495) 9659f082 is described below commit 9659f082c59ce4535d6e0ab9bd7867c9121c0a4d Author: michieldwitte <michieldwi...@gmail.com> AuthorDate: Sat Apr 19 04:03:09 2025 +0200 Ensure messages are delivered by TelnetAppender when the socket is in a TIME_WAIT state (#495) Co-authored-by: Michiel De Witte <michiel.dewi...@basalte.be> --- src/main/cpp/aprserversocket.cpp | 16 +++++++++++++++- src/main/cpp/serversocket.cpp | 6 ++++++ src/main/cpp/telnetappender.cpp | 12 +++++++++++- src/main/include/log4cxx/helpers/serversocket.h | 5 +++++ src/main/include/log4cxx/net/telnetappender.h | 12 ++++++++++++ src/main/include/log4cxx/private/aprserversocket.h | 5 +++++ src/test/cpp/net/socketappendertestcase.cpp | 2 +- src/test/cpp/net/telnetappendertestcase.cpp | 1 + 8 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/main/cpp/aprserversocket.cpp b/src/main/cpp/aprserversocket.cpp index e9d49c0c..b7bd27f5 100644 --- a/src/main/cpp/aprserversocket.cpp +++ b/src/main/cpp/aprserversocket.cpp @@ -35,7 +35,12 @@ struct APRServerSocket::APRServerSocketPriv : public ServerSocketPrivate { apr_socket_t* socket; }; -APRServerSocket::APRServerSocket(int port) : +#if LOG4CXX_ABI_VERSION <= 15 +APRServerSocket::APRServerSocket(int port) : + APRServerSocket(port, false) {} +#endif + +APRServerSocket::APRServerSocket(int port, bool reuseAddress) : ServerSocket(std::make_unique<APRServerSocketPriv>()){ apr_status_t status = apr_socket_create(&_priv->socket, APR_INET, SOCK_STREAM, @@ -53,6 +58,15 @@ APRServerSocket::APRServerSocket(int port) : throw SocketException(status); } + if (reuseAddress) { + apr_status_t status = apr_socket_opt_set(_priv->socket, APR_SO_REUSEADDR, 1); + + if (status != APR_SUCCESS) + { + throw SocketException(status); + } + } + // Create server socket address (including port number) apr_sockaddr_t* server_addr; status = diff --git a/src/main/cpp/serversocket.cpp b/src/main/cpp/serversocket.cpp index 1a12ec84..e696bd1c 100644 --- a/src/main/cpp/serversocket.cpp +++ b/src/main/cpp/serversocket.cpp @@ -51,6 +51,12 @@ void ServerSocket::setSoTimeout(int newVal) m_priv->timeout = newVal; } +#if LOG4CXX_ABI_VERSION <= 15 ServerSocketUniquePtr ServerSocket::create(int port){ return std::make_unique<APRServerSocket>(port); } +#endif + +ServerSocketUniquePtr ServerSocket::create(int port, bool reuseAddress){ + return std::make_unique<APRServerSocket>(port, reuseAddress); +} diff --git a/src/main/cpp/telnetappender.cpp b/src/main/cpp/telnetappender.cpp index d012f66f..aa1374cd 100644 --- a/src/main/cpp/telnetappender.cpp +++ b/src/main/cpp/telnetappender.cpp @@ -58,6 +58,7 @@ struct TelnetAppender::TelnetAppenderPriv : public AppenderSkeletonPrivate { stopAcceptingConnections(); } int port; + bool reuseAddress = false; ConnectionList connections; LogString encoding; LOG4CXX_NS::helpers::CharsetEncoderPtr encoder; @@ -112,7 +113,7 @@ void TelnetAppender::activateOptions(Pool& /* p */) { if (_priv->serverSocket == NULL) { - _priv->serverSocket = ServerSocket::create(_priv->port); + _priv->serverSocket = ServerSocket::create(_priv->port, _priv->reuseAddress); _priv->serverSocket->setSoTimeout(1000); } @@ -135,6 +136,10 @@ void TelnetAppender::setOption(const LogString& option, { setEncoding(value); } + else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("REUSEADDRESS"), LOG4CXX_STR("reuseaddress"))) + { + setReuseAddress(OptionConverter::toBoolean(value, true)); + } else { AppenderSkeleton::setOption(option, value); @@ -358,6 +363,11 @@ void TelnetAppender::setMaxConnections(int newValue) } } +void TelnetAppender::setReuseAddress(bool reuseAddress) +{ + _priv->reuseAddress = reuseAddress; +} + bool TelnetAppender::requiresLayout() const { return false; diff --git a/src/main/include/log4cxx/helpers/serversocket.h b/src/main/include/log4cxx/helpers/serversocket.h index aad824a3..5b7bd4a1 100644 --- a/src/main/include/log4cxx/helpers/serversocket.h +++ b/src/main/include/log4cxx/helpers/serversocket.h @@ -57,7 +57,12 @@ class LOG4CXX_EXPORT ServerSocket */ void setSoTimeout(int timeout); +#if LOG4CXX_ABI_VERSION <= 15 static ServerSocketUniquePtr create(int port); + static ServerSocketUniquePtr create(int port, bool reuseAddress); +#else + static ServerSocketUniquePtr create(int port, bool reuseAddress = false); +#endif }; } // namespace helpers diff --git a/src/main/include/log4cxx/net/telnetappender.h b/src/main/include/log4cxx/net/telnetappender.h index 6af888c4..a35169b1 100644 --- a/src/main/include/log4cxx/net/telnetappender.h +++ b/src/main/include/log4cxx/net/telnetappender.h @@ -42,6 +42,9 @@ especially when monitoring a servlet remotely. If no layout is provided, the log message only is sent to attached client(s). +The ReuseAddress option is disabled by default, +enable it if you want it to be able to bind to the address immediately after restarting / crashing + See TelnetAppender::setOption() for the available options. */ @@ -96,6 +99,7 @@ class LOG4CXX_EXPORT TelnetAppender : public AppenderSkeleton Port | {int} | 23 MaxConnections | {int} | 20 Encoding | C,UTF-8,UTF-16,UTF-16BE,UTF-16LE,646,US-ASCII,ISO646-US,ANSI_X3.4-1968,ISO-8859-1,ISO-LATIN-1 | UTF-8 + ReuseAddress | True,False | True \sa AppenderSkeleton::setOption() */ @@ -125,6 +129,14 @@ class LOG4CXX_EXPORT TelnetAppender : public AppenderSkeleton */ void setMaxConnections(int newValue); + /** + Set the SO_REUSEADDR option to of the server socket. + This allows the socket to bind to an address that is in a TIME_WAIT state. + This is useful for restarting immediately after it has been closed. + + \sa setOption + */ + void setReuseAddress(bool reuseAddress); /** Shutdown this appender. */ void close() override; diff --git a/src/main/include/log4cxx/private/aprserversocket.h b/src/main/include/log4cxx/private/aprserversocket.h index 07984d17..d8b3617f 100644 --- a/src/main/include/log4cxx/private/aprserversocket.h +++ b/src/main/include/log4cxx/private/aprserversocket.h @@ -31,7 +31,12 @@ namespace helpers class LOG4CXX_EXPORT APRServerSocket : public helpers::ServerSocket { public: +#if LOG4CXX_ABI_VERSION <= 15 APRServerSocket(int port); + APRServerSocket(int port, bool reuseAddress); +#else + APRServerSocket(int port, bool reuseAddress = false); +#endif void close() override; diff --git a/src/test/cpp/net/socketappendertestcase.cpp b/src/test/cpp/net/socketappendertestcase.cpp index 2d5accdd..607863f2 100644 --- a/src/test/cpp/net/socketappendertestcase.cpp +++ b/src/test/cpp/net/socketappendertestcase.cpp @@ -80,7 +80,7 @@ class SocketAppenderTestCase : public AppenderSkeletonTestCase helpers::ServerSocketUniquePtr serverSocket; try { - serverSocket = helpers::ServerSocket::create(tcpPort); + serverSocket = helpers::ServerSocket::create(tcpPort, true); } catch (std::exception& ex) { diff --git a/src/test/cpp/net/telnetappendertestcase.cpp b/src/test/cpp/net/telnetappendertestcase.cpp index b7aebbe5..1e5a7437 100644 --- a/src/test/cpp/net/telnetappendertestcase.cpp +++ b/src/test/cpp/net/telnetappendertestcase.cpp @@ -105,6 +105,7 @@ class TelnetAppenderTestCase : public AppenderSkeletonTestCase TelnetAppenderPtr appender(new TelnetAppender()); appender->setPort(TEST_PORT); appender->setMaxConnections(1); + appender->setReuseAddress(true); Pool p; appender->activateOptions(p); LoggerPtr root(Logger::getRootLogger());