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());

Reply via email to