Hello list,

we had some problems with qpid-0.14 (i know, it's ancient -:): lots of orphaned connections (open on qpid-server but not on the client side) due firewalls, i guess.

To mitigate the problem i wrote a patch for qpid-cpp implementing a new option --tcp-keepalive (similar to --tcp-nodelay) which sets SO_KEEPALIVE. Enabling keep_alive "solved" our issue but i'm not sure what to do with the patch because it's for an old version and needs some rewriting for the current version of qpid. Unfortunately i'm unable to adapt it to the current version for various reasons:

- i'm no developer, i barely scratch my itches
- lack of time

So i simply post the patch here, maybe someone else has plans to add keepalive in trunk and maybe the patch helps.

Regards,
-ap

diff -Purp qpid-0.14.org/cpp/bindings/qpid/ruby/lib/qpid/connection.rb qpid-0.14/cpp/bindings/qpid/ruby/lib/qpid/connection.rb
--- qpid-0.14.org/cpp/bindings/qpid/ruby/lib/qpid/connection.rb	2011-07-15 19:03:35.000000000 +0200
+++ qpid-0.14/cpp/bindings/qpid/ruby/lib/qpid/connection.rb	2014-02-25 14:31:47.263619537 +0100
@@ -32,6 +32,7 @@ module Qpid
       # password::
       # heartbeat::
       # tcp_nodelay::
+      # tcp_keepalive::
       # sasl_mechanism::
       # sasl_service::
       # sasl_min_ssf::
diff -Purp qpid-0.14.org/cpp/include/qpid/client/ConnectionSettings.h qpid-0.14/cpp/include/qpid/client/ConnectionSettings.h
--- qpid-0.14.org/cpp/include/qpid/client/ConnectionSettings.h	2011-05-17 23:02:34.000000000 +0200
+++ qpid-0.14/cpp/include/qpid/client/ConnectionSettings.h	2014-02-25 14:31:47.263619537 +0100
@@ -109,6 +109,10 @@ struct QPID_CLIENT_CLASS_EXTERN Connecti
      */
     bool tcpNoDelay;
     /**
+     * If true, TCP_KEEPALIVE will be set for the connection.
+     */
+    bool tcpKeepAlive;
+    /**
      * SASL service name
      */
     std::string service;
diff -Purp qpid-0.14.org/cpp/include/qpid/management/ConnectionSettings.h qpid-0.14/cpp/include/qpid/management/ConnectionSettings.h
--- qpid-0.14.org/cpp/include/qpid/management/ConnectionSettings.h	2010-05-25 16:02:49.000000000 +0200
+++ qpid-0.14/cpp/include/qpid/management/ConnectionSettings.h	2014-02-25 14:31:47.271619721 +0100
@@ -97,6 +97,10 @@ struct ConnectionSettings {
      */
     bool tcpNoDelay;
     /**
+     * If true, TCP_KEEPALIVE will be set for the connection.
+     */
+    bool tcpKeepAlive;
+    /**
      * SASL service name
      */
     std::string service;
diff -Purp qpid-0.14.org/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp qpid-0.14/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp
--- qpid-0.14.org/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp	2009-10-20 17:22:19.000000000 +0200
+++ qpid-0.14/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp	2014-02-25 14:31:47.277619859 +0100
@@ -37,6 +37,7 @@ const string attrMaxChannels("maxChannel
 const string attrMaxFrameSize("maxFrameSize");
 const string attrBounds("bounds");
 const string attrTcpNoDelay("tcpNoDelay");
+const string attrTcpKeepAlive("tcpKeepAlive");
 const string attrService("service");
 const string attrMinSsf("minSsf");
 const string attrMaxSsf("maxSsf");
@@ -71,6 +72,7 @@ bool ConnectionSettingsImpl::setAttr(con
     else if (key == attrMaxFrameSize) clientSettings.maxFrameSize = value.asUint();
     else if (key == attrBounds)       clientSettings.bounds       = value.asUint();
     else if (key == attrTcpNoDelay)   clientSettings.tcpNoDelay   = value.asBool();
+    else if (key == attrTcpKeepAlive) clientSettings.tcpKeepAlive = value.asBool();
     else if (key == attrService)      clientSettings.service      = value.asString();
     else if (key == attrMinSsf)       clientSettings.minSsf       = value.asUint();
     else if (key == attrMaxSsf)       clientSettings.maxSsf       = value.asUint();
@@ -155,6 +157,11 @@ Value ConnectionSettingsImpl::getAttr(co
         return boolval;
     }
 
+    if (key == attrTcpKeepAlive) {
+        boolval.setBool(clientSettings.tcpKeepAlive);
+        return boolval;
+    }
+
     if (key == attrService) {
         strval.setString(clientSettings.service.c_str());
         return strval;
diff -Purp qpid-0.14.org/cpp/src/qpid/agent/ManagementAgentImpl.cpp qpid-0.14/cpp/src/qpid/agent/ManagementAgentImpl.cpp
--- qpid-0.14.org/cpp/src/qpid/agent/ManagementAgentImpl.cpp	2011-08-15 18:47:56.000000000 +0200
+++ qpid-0.14/cpp/src/qpid/agent/ManagementAgentImpl.cpp	2014-02-25 14:31:47.284620020 +0100
@@ -207,6 +207,7 @@ void ManagementAgentImpl::init(const qpi
     connectionSettings.maxFrameSize = settings.maxFrameSize;
     connectionSettings.bounds       = settings.bounds;
     connectionSettings.tcpNoDelay   = settings.tcpNoDelay;
+    connectionSettings.tcpKeepAlive = settings.tcpKeepAlive;
     connectionSettings.service      = settings.service;
     connectionSettings.minSsf       = settings.minSsf;
     connectionSettings.maxSsf       = settings.maxSsf;
diff -Purp qpid-0.14.org/cpp/src/qpid/broker/Broker.cpp qpid-0.14/cpp/src/qpid/broker/Broker.cpp
--- qpid-0.14.org/cpp/src/qpid/broker/Broker.cpp	2014-02-25 14:31:19.929969910 +0100
+++ qpid-0.14/cpp/src/qpid/broker/Broker.cpp	2014-02-25 14:31:47.290620158 +0100
@@ -119,6 +119,7 @@ Broker::Options::Options(const std::stri
     replayHardLimit(0),
     queueLimit(100*1048576/*100M default limit*/),
     tcpNoDelay(false),
+    tcpKeepAlive(false),
     requireEncrypted(false),
     maxSessionRate(0),
     asyncQueueEvents(false),     // Must be false in a cluster.
@@ -159,6 +160,7 @@ Broker::Options::Options(const std::stri
         ("realm", optValue(realm, "REALM"), "Use the given realm when performing authentication")
         ("default-queue-limit", optValue(queueLimit, "BYTES"), "Default maximum size for queues (in bytes)")
         ("tcp-nodelay", optValue(tcpNoDelay), "Set TCP_NODELAY on TCP connections")
+        ("tcp-keepalive", optValue(tcpKeepAlive), "Set TCP_KEEPALIVE on TCP connections")
         ("require-encryption", optValue(requireEncrypted), "Only accept connections that are encrypted")
         ("known-hosts-url", optValue(knownHosts, "URL or 'none'"), "URL to send as 'known-hosts' to clients ('none' implies empty list)")
         ("sasl-config", optValue(saslConfigPath, "DIR"), "gets sasl config info from nonstandard location")
diff -Purp qpid-0.14.org/cpp/src/qpid/broker/Broker.h qpid-0.14/cpp/src/qpid/broker/Broker.h
--- qpid-0.14.org/cpp/src/qpid/broker/Broker.h	2014-02-25 14:31:19.355956709 +0100
+++ qpid-0.14/cpp/src/qpid/broker/Broker.h	2014-02-25 14:31:47.296620296 +0100
@@ -113,6 +113,7 @@ public:
         size_t replayHardLimit;
         uint queueLimit;
         bool tcpNoDelay;
+        bool tcpKeepAlive;
         bool requireEncrypted;
         std::string knownHosts;
         std::string saslConfigPath;
diff -Purp qpid-0.14.org/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp qpid-0.14/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp
--- qpid-0.14.org/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp	2014-02-25 14:31:18.757942712 +0100
+++ qpid-0.14/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp	2014-02-25 14:42:42.997187345 +0100
@@ -81,6 +81,7 @@ class SslProtocolFactory : public qpid::
     uint32_t maxNegotiateTime;
     uint16_t listeningPort;
     const bool tcpNoDelay;
+    const bool tcpKeepAlive;
     std::string brokerHost;
     const bool clientAuthSelected;
     std::auto_ptr<qpid::sys::AsynchAcceptor> acceptor;
@@ -89,7 +90,7 @@ class SslProtocolFactory : public qpid::
 
   public:
     SslProtocolFactory(const SslServerOptions&, const std::string& host, const std::string& port,
-                       int backlog, bool nodelay,
+                       int backlog, bool nodelay, bool keepalive,
                        Timer& timer, uint32_t maxTime);
     ~SslProtocolFactory();
     void accept(sys::Poller::shared_ptr, sys::ConnectionCodec::Factory*);
@@ -127,7 +128,7 @@ static struct SslPlugin : public Plugin 
                 const broker::Broker::Options& opts = broker->getOptions();
                 ProtocolFactory::shared_ptr protocol(new SslProtocolFactory(options,
                                                                             "", boost::lexical_cast<std::string>(options.port),
-                                                                            opts.connectionBacklog, opts.tcpNoDelay,
+                                                                            opts.connectionBacklog, opts.tcpNoDelay, opts.tcpKeepAlive,
                                                                             broker->getTimer(), opts.maxNegotiateTime));
                 QPID_LOG(notice, "Listening for SSL connections on TCP port " << protocol->getPort());
                 broker->registerProtocolFactory("ssl", protocol);
@@ -140,11 +141,12 @@ static struct SslPlugin : public Plugin 
 
 SslProtocolFactory::SslProtocolFactory(const SslServerOptions& options,
                                        const std::string& host, const std::string& port,
-                                       int backlog, bool nodelay,
+                                       int backlog, bool nodelay, bool keepalive,
                                        Timer& timer, uint32_t maxTime)
     : brokerTimer(timer),
       maxNegotiateTime(maxTime),
       tcpNoDelay(nodelay),
+      tcpKeepAlive(keepalive),
       clientAuthSelected(options.clientAuth) {
 
     // Make sure that certificate store is good before listening to sockets
@@ -235,6 +237,12 @@ void SslProtocolFactory::established(sys
                  "Set TCP_NODELAY on connection to " << s.getPeerAddress());
     }
 
+    if (tcpKeepAlive) {
+        s.setTcpKeepAlive();
+        QPID_LOG(info,
+                 "Set TCP_KEEPALIVE on connection to " << s.getPeerAddress());
+    }
+
     SslAsynchIO *aio;
     if (isClient) {
         async->setClient();
diff -Purp qpid-0.14.org/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp qpid-0.14/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
--- qpid-0.14.org/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp	2014-02-25 14:31:19.090950614 +0100
+++ qpid-0.14/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp	2014-02-25 14:31:47.310620618 +0100
@@ -123,6 +123,8 @@ void ConnectionImpl::setOption(const std
         settings.heartbeat = value;
     } else if (name == "tcp-nodelay" || name == "tcp_nodelay") {
         settings.tcpNoDelay = value;
+    } else if (name == "tcp-keepalive" || name == "tcp_keepalive") {
+        settings.tcpKeepAlive = value;
     } else if (name == "locale") {
         settings.locale = value.asString();
     } else if (name == "max-channels" || name == "max_channels") {
diff -Purp qpid-0.14.org/cpp/src/qpid/client/ConnectionSettings.cpp qpid-0.14/cpp/src/qpid/client/ConnectionSettings.cpp
--- qpid-0.14.org/cpp/src/qpid/client/ConnectionSettings.cpp	2011-02-02 17:00:51.000000000 +0100
+++ qpid-0.14/cpp/src/qpid/client/ConnectionSettings.cpp	2014-02-25 14:31:47.316620756 +0100
@@ -38,6 +38,7 @@ ConnectionSettings::ConnectionSettings()
     maxFrameSize(65535),
     bounds(2),
     tcpNoDelay(false),
+    tcpKeepAlive(false),
     service(qpid::saslName),
     minSsf(0),
     maxSsf(256),
@@ -52,6 +53,10 @@ void ConnectionSettings::configureSocket
         socket.setTcpNoDelay();
         QPID_LOG(info, "Set TCP_NODELAY");
     }
+    if (tcpKeepAlive) {
+        socket.setTcpKeepAlive();
+        QPID_LOG(info, "Set TCP_KEEPALIVE");
+    }
 }
 
 }} // namespace qpid::client
diff -Purp qpid-0.14.org/cpp/src/qpid/management/ConnectionSettings.cpp qpid-0.14/cpp/src/qpid/management/ConnectionSettings.cpp
--- qpid-0.14.org/cpp/src/qpid/management/ConnectionSettings.cpp	2010-05-25 16:02:49.000000000 +0200
+++ qpid-0.14/cpp/src/qpid/management/ConnectionSettings.cpp	2014-02-25 14:31:47.322620894 +0100
@@ -31,6 +31,7 @@ qpid::management::ConnectionSettings::Co
     maxFrameSize(65535),
     bounds(2),
     tcpNoDelay(false),
+    tcpKeepAlive(false),
     service(qpid::saslName),
     minSsf(0),
     maxSsf(256)
diff -Purp qpid-0.14.org/cpp/src/qpid/sys/posix/Socket.cpp qpid-0.14/cpp/src/qpid/sys/posix/Socket.cpp
--- qpid-0.14.org/cpp/src/qpid/sys/posix/Socket.cpp	2014-02-25 14:31:19.494959904 +0100
+++ qpid-0.14/cpp/src/qpid/sys/posix/Socket.cpp	2014-02-25 14:31:47.326620986 +0100
@@ -70,13 +70,15 @@ uint16_t getLocalPort(int fd)
 Socket::Socket() :
     IOHandle(new IOHandlePrivate),
     nonblocking(false),
-    nodelay(false)
+    nodelay(false),
+    keepalive(false)
 {}
 
 Socket::Socket(IOHandlePrivate* h) :
     IOHandle(h),
     nonblocking(false),
-    nodelay(false)
+    nodelay(false),
+    keepalive(false)
 {}
 
 void Socket::createSocket(const SocketAddress& sa) const
@@ -90,6 +92,7 @@ void Socket::createSocket(const SocketAd
     try {
         if (nonblocking) setNonblocking();
         if (nodelay) setTcpNoDelay();
+        if (keepalive) setTcpKeepAlive();
         if (getAddrInfo(sa).ai_family == AF_INET6) {
             int flag = 1;
             int result = ::setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&flag, sizeof(flag));
@@ -135,6 +138,17 @@ void Socket::setTcpNoDelay() const
     }
 }
 
+void Socket::setTcpKeepAlive() const
+{
+    int& socket = impl->fd;
+    keepalive = true;
+    if (socket != -1) {
+        int flag = 1;
+        int result = ::setsockopt(impl->fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&flag, sizeof(flag));
+        QPID_POSIX_CHECK(result);
+    }
+}
+
 void Socket::connect(const std::string& host, const std::string& port) const
 {
     SocketAddress sa(host, port);
diff -Purp qpid-0.14.org/cpp/src/qpid/sys/Socket.h qpid-0.14/cpp/src/qpid/sys/Socket.h
--- qpid-0.14.org/cpp/src/qpid/sys/Socket.h	2011-10-20 21:40:34.000000000 +0200
+++ qpid-0.14/cpp/src/qpid/sys/Socket.h	2014-02-25 14:31:47.332621124 +0100
@@ -46,6 +46,7 @@ public:
     void setNonblocking() const;
 
     QPID_COMMON_EXTERN void setTcpNoDelay() const;
+    QPID_COMMON_EXTERN void setTcpKeepAlive() const;
 
     QPID_COMMON_EXTERN void connect(const std::string& host, const std::string& port) const;
     QPID_COMMON_EXTERN void connect(const SocketAddress&) const;
@@ -104,6 +105,7 @@ protected:
     mutable std::string peername;
     mutable bool nonblocking;
     mutable bool nodelay;
+    mutable bool keepalive;
 };
 
 }}
diff -Purp qpid-0.14.org/cpp/src/qpid/sys/ssl/SslSocket.cpp qpid-0.14/cpp/src/qpid/sys/ssl/SslSocket.cpp
--- qpid-0.14.org/cpp/src/qpid/sys/ssl/SslSocket.cpp	2011-10-20 21:40:34.000000000 +0200
+++ qpid-0.14/cpp/src/qpid/sys/ssl/SslSocket.cpp	2014-02-25 14:31:47.338621262 +0100
@@ -346,6 +346,16 @@ void SslSocket::setTcpNoDelay(bool nodel
     }
 }
 
+void SslSocket::setTcpKeepAlive(bool keepalive) const
+{
+    if (keepalive) {
+        PRSocketOptionData option;
+        option.option = PR_SockOpt_Keepalive;
+        option.value.keep_alive = true;
+        PR_SetSocketOption(socket, &option);
+    }
+}
+
 void SslSocket::setCertName(const std::string& name)
 {
     certname = name;
diff -Purp qpid-0.14.org/cpp/src/qpid/sys/ssl/SslSocket.h qpid-0.14/cpp/src/qpid/sys/ssl/SslSocket.h
--- qpid-0.14.org/cpp/src/qpid/sys/ssl/SslSocket.h	2011-10-20 21:40:34.000000000 +0200
+++ qpid-0.14/cpp/src/qpid/sys/ssl/SslSocket.h	2014-02-25 14:31:47.344621400 +0100
@@ -49,6 +49,9 @@ public:
     /** Set tcp-nodelay */
     void setTcpNoDelay(bool nodelay) const;
 
+    /** Set tcp-nodelay */
+    void setTcpKeepAlive(bool keepalive) const;
+
     /** Set SSL cert-name. Allows the cert-name to be set per
      * connection, overriding global cert-name settings from
      * NSSInit().*/
diff -Purp qpid-0.14.org/cpp/src/qpid/sys/SslPlugin.cpp qpid-0.14/cpp/src/qpid/sys/SslPlugin.cpp
--- qpid-0.14.org/cpp/src/qpid/sys/SslPlugin.cpp	2014-02-25 14:31:18.763942856 +0100
+++ qpid-0.14/cpp/src/qpid/sys/SslPlugin.cpp	2014-02-25 14:40:17.228729149 +0100
@@ -73,13 +73,14 @@ class SslProtocolFactoryTmpl : public Pr
     Timer& brokerTimer;
     uint32_t maxNegotiateTime;
     const bool tcpNoDelay;
+    const bool tcpKeepAlive;
     T listener;
     const uint16_t listeningPort;
     std::auto_ptr<SslAcceptor> acceptor;
     bool nodict;
 
   public:
-    SslProtocolFactoryTmpl(const SslServerOptions&, int backlog, bool nodelay, Timer& timer, uint32_t maxTime);
+    SslProtocolFactoryTmpl(const SslServerOptions&, int backlog, bool nodelay, bool keepalive, Timer& timer, uint32_t maxTime);
     void accept(Poller::shared_ptr, ConnectionCodec::Factory*);
     void connect(Poller::shared_ptr, const std::string& host, const std::string& port,
                  ConnectionCodec::Factory*,
@@ -143,10 +144,12 @@ static struct SslPlugin : public Plugin 
                         static_cast<ProtocolFactory*>(new SslMuxProtocolFactory(options,
                                                   opts.connectionBacklog,
                                                   opts.tcpNoDelay,
+                                                  opts.tcpKeepAlive,
                                                   broker->getTimer(), opts.maxNegotiateTime)) :
                         static_cast<ProtocolFactory*>(new SslProtocolFactory(options,
                                                opts.connectionBacklog,
                                                opts.tcpNoDelay,
+                                               opts.tcpKeepAlive,
                                                broker->getTimer(), opts.maxNegotiateTime)));
                     QPID_LOG(notice, "Listening for " <<
                                      (options.multiplex ? "SSL or TCP" : "SSL") <<
@@ -162,16 +165,16 @@ static struct SslPlugin : public Plugin 
 } sslPlugin;
 
 template <class T>
-SslProtocolFactoryTmpl<T>::SslProtocolFactoryTmpl(const SslServerOptions& options, int backlog, bool nodelay, Timer& timer, uint32_t maxTime) :
+SslProtocolFactoryTmpl<T>::SslProtocolFactoryTmpl(const SslServerOptions& options, int backlog, bool nodelay, bool keepalive, Timer& timer, uint32_t maxTime) :
     brokerTimer(timer),
     maxNegotiateTime(maxTime),
-    tcpNoDelay(nodelay), listeningPort(listener.listen(options.port, backlog, options.certName, options.clientAuth)),
+    tcpNoDelay(nodelay), tcpKeepAlive(keepalive), listeningPort(listener.listen(options.port, backlog, options.certName, options.clientAuth)),
     nodict(options.nodict)
 {}
 
 void SslEstablished(Poller::shared_ptr poller, const qpid::sys::SslSocket& s,
                     ConnectionCodec::Factory* f, bool isClient,
-                    Timer& timer, uint32_t maxTime, bool tcpNoDelay, bool nodict) {
+                    Timer& timer, uint32_t maxTime, bool tcpNoDelay, bool tcpKeepAlive, bool nodict) {
     qpid::sys::ssl::SslHandler* async = new qpid::sys::ssl::SslHandler(s.getFullAddress(), f, nodict);
 
     if (tcpNoDelay) {
@@ -179,6 +182,11 @@ void SslEstablished(Poller::shared_ptr p
         QPID_LOG(info, "Set TCP_NODELAY on connection to " << s.getPeerAddress());
     }
 
+    if (tcpKeepAlive) {
+        s.setTcpKeepAlive(tcpKeepAlive);
+        QPID_LOG(info, "Set TCP_KEEPALIVE on connection to " << s.getPeerAddress());
+    }
+
     if (isClient) {
         async->setClient();
     }
@@ -200,7 +208,7 @@ void SslProtocolFactory::established(Pol
                                      ConnectionCodec::Factory* f, bool isClient) {
     const SslSocket *sslSock = dynamic_cast<const SslSocket*>(&s);
 
-    SslEstablished(poller, *sslSock, f, isClient, brokerTimer, maxNegotiateTime, tcpNoDelay, nodict);
+    SslEstablished(poller, *sslSock, f, isClient, brokerTimer, maxNegotiateTime, tcpNoDelay, tcpKeepAlive, nodict);
 }
 
 template <class T>
@@ -224,7 +232,7 @@ void SslMuxProtocolFactory::established(
     const SslSocket *sslSock = dynamic_cast<const SslSocket*>(&s);
 
     if (sslSock) {
-        SslEstablished(poller, *sslSock, f, isClient, brokerTimer, maxNegotiateTime, tcpNoDelay, nodict);
+        SslEstablished(poller, *sslSock, f, isClient, brokerTimer, maxNegotiateTime, tcpNoDelay, tcpKeepAlive, nodict);
         return;
     }
 
@@ -235,6 +243,11 @@ void SslMuxProtocolFactory::established(
         QPID_LOG(info, "Set TCP_NODELAY on connection to " << s.getPeerAddress());
     }
 
+    if (tcpKeepAlive) {
+        s.setTcpKeepAlive();
+        QPID_LOG(info, "Set TCP_KEEPALIVE on connection to " << s.getPeerAddress());
+    }
+
     if (isClient) {
         async->setClient();
     }
diff -Purp qpid-0.14.org/cpp/src/qpid/sys/TCPIOPlugin.cpp qpid-0.14/cpp/src/qpid/sys/TCPIOPlugin.cpp
--- qpid-0.14.org/cpp/src/qpid/sys/TCPIOPlugin.cpp	2014-02-25 14:31:18.770943024 +0100
+++ qpid-0.14/cpp/src/qpid/sys/TCPIOPlugin.cpp	2014-02-25 14:36:00.196625616 +0100
@@ -45,10 +45,11 @@ class AsynchIOProtocolFactory : public P
     uint32_t maxNegotiateTime;
     uint16_t listeningPort;
     const bool tcpNoDelay;
+    const bool tcpKeepAlive;
 
   public:
     AsynchIOProtocolFactory(const std::string& host, const std::string& port,
-                            int backlog, bool nodelay,
+                            int backlog, bool nodelay, bool keepalive,
                             Timer& timer, uint32_t maxTime,
                             bool shouldListen);
     void accept(Poller::shared_ptr, ConnectionCodec::Factory*);
@@ -97,6 +98,7 @@ static class TCPIOPlugin : public Plugin
                     "", boost::lexical_cast<std::string>(opts.port),
                     opts.connectionBacklog,
                     opts.tcpNoDelay,
+                    opts.tcpKeepAlive,
                     broker->getTimer(), opts.maxNegotiateTime,
                     shouldListen));
 
@@ -110,12 +112,13 @@ static class TCPIOPlugin : public Plugin
 } tcpPlugin;
 
 AsynchIOProtocolFactory::AsynchIOProtocolFactory(const std::string& host, const std::string& port,
-                                                 int backlog, bool nodelay,
+                                                 int backlog, bool nodelay, bool keepalive,
                                                  Timer& timer, uint32_t maxTime,
                                                  bool shouldListen) :
     brokerTimer(timer),
     maxNegotiateTime(maxTime),
-    tcpNoDelay(nodelay)
+    tcpNoDelay(nodelay),
+    tcpKeepAlive(keepalive)
 {
     if (!shouldListen) {
         listeningPort = boost::lexical_cast<uint16_t>(port);
@@ -155,6 +158,11 @@ void AsynchIOProtocolFactory::establishe
         QPID_LOG(info, "Set TCP_NODELAY on connection to " << s.getPeerAddress());
     }
 
+    if (tcpKeepAlive) {
+        s.setTcpKeepAlive();
+        QPID_LOG(info, "Set TCP_KEEPALIVE on connection to " << s.getPeerAddress());
+    }
+
     if (isClient)
         async->setClient();
     AsynchIO* aio = AsynchIO::create
diff -Purp qpid-0.14.org/cpp/src/qpid/sys/windows/Socket.cpp qpid-0.14/cpp/src/qpid/sys/windows/Socket.cpp
--- qpid-0.14.org/cpp/src/qpid/sys/windows/Socket.cpp	2014-02-25 14:31:19.053949763 +0100
+++ qpid-0.14/cpp/src/qpid/sys/windows/Socket.cpp	2014-02-25 14:31:47.364621860 +0100
@@ -113,13 +113,15 @@ uint16_t getLocalPort(int fd)
 Socket::Socket() :
     IOHandle(new IOHandlePrivate),
     nonblocking(false),
-    nodelay(false)
+    nodelay(false),
+    keepalive(false)
 {}
 
 Socket::Socket(IOHandlePrivate* h) :
     IOHandle(h),
     nonblocking(false),
-    nodelay(false)
+    nodelay(false),
+    keepalive(false)
 {}
 
 void Socket::createSocket(const SocketAddress& sa) const
@@ -136,6 +138,7 @@ void Socket::createSocket(const SocketAd
     try {
         if (nonblocking) setNonblocking();
         if (nodelay) setTcpNoDelay();
+        if (keepalive) setTcpKeepAlive();
     } catch (std::exception&) {
         ::closesocket(s);
         socket = INVALID_SOCKET;
@@ -283,6 +286,18 @@ void Socket::setTcpNoDelay() const
     }
 }
 
+void Socket::setTcpKeepAlive() const
+{
+    int flag = 1;
+    int result = setsockopt(impl->fd,
+                            SOL_SOCKET,
+                            SO_KEEPALIVE,
+                            (char *)&flag,
+                            sizeof(flag));
+    QPID_WINSOCK_CHECK(result);
+    keepalive = true;
+}
+
 inline IOHandlePrivate* IOHandlePrivate::getImpl(const qpid::sys::IOHandle &h)
 {
     return h.impl;
diff -Purp qpid-0.14.org/cpp/src/tests/ConnectionOptions.h qpid-0.14/cpp/src/tests/ConnectionOptions.h
--- qpid-0.14.org/cpp/src/tests/ConnectionOptions.h	2010-05-12 15:41:32.000000000 +0200
+++ qpid-0.14/cpp/src/tests/ConnectionOptions.h	2014-02-25 14:31:47.368621952 +0100
@@ -51,6 +51,7 @@ struct  ConnectionOptions : public qpid:
             ("bounds-multiplier", optValue(bounds, "N"),
              "bound size of write queue (as a multiple of the max frame size).")
             ("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay")
+            ("tcp-keepalive", optValue(tcpKeepAlive), "Turn on tcp-keepalive")
             ("service", optValue(service, "SERVICE-NAME"), "SASL service name.")
             ("min-ssf", optValue(minSsf, "N"), "Minimum acceptable strength for SASL security layer")
 	    ("max-ssf", optValue(maxSsf, "N"), "Maximum acceptable strength for SASL security layer");
diff -Purp qpid-0.14.org/cpp/src/tests/echotest.cpp qpid-0.14/cpp/src/tests/echotest.cpp
--- qpid-0.14.org/cpp/src/tests/echotest.cpp	2010-04-23 05:59:52.000000000 +0200
+++ qpid-0.14/cpp/src/tests/echotest.cpp	2014-02-25 14:31:47.374622090 +0100
@@ -58,6 +58,7 @@ struct  Args : public qpid::Options,
             ("password", optValue(password, "PASSWORD"), "password for broker log in.")
             ("mechanism", optValue(mechanism, "MECH"), "SASL mechanism to use when authenticating.")
             ("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay")
+            ("tcp-keepalive", optValue(tcpKeepAlive), "Turn on tcp-keepalive")
             ("s,summary", optValue(summary), "Print only average latency.");
     }
 };
diff -Purp qpid-0.14.org/python/qpid/messaging/endpoints.py qpid-0.14/python/qpid/messaging/endpoints.py
--- qpid-0.14.org/python/qpid/messaging/endpoints.py	2014-02-25 14:31:19.548961147 +0100
+++ qpid-0.14/python/qpid/messaging/endpoints.py	2014-02-25 14:31:47.381622251 +0100
@@ -166,6 +166,7 @@ class Connection(Endpoint):
 
     self.address_ttl = options.get("address_ttl", 60)
     self.tcp_nodelay = options.get("tcp_nodelay", False)
+    self.tcp_keepalive = options.get("tcp_keepalive", False)
 
     self.ssl_keyfile = options.get("ssl_keyfile", None)
     self.ssl_certfile = options.get("ssl_certfile", None)
diff -Purp qpid-0.14.org/python/qpid/messaging/transports.py qpid-0.14/python/qpid/messaging/transports.py
--- qpid-0.14.org/python/qpid/messaging/transports.py	2011-03-17 13:47:00.000000000 +0100
+++ qpid-0.14/python/qpid/messaging/transports.py	2014-02-25 14:31:47.384622320 +0100
@@ -28,6 +28,8 @@ class SocketTransport:
     self.socket = connect(host, port)
     if conn.tcp_nodelay:
       self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+    if conn.tcp_keepalive:
+      self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
 
   def fileno(self):
     return self.socket.fileno()
diff -Purp qpid-0.14.org/python/qpid/tests/messaging/endpoints.py qpid-0.14/python/qpid/tests/messaging/endpoints.py
--- qpid-0.14.org/python/qpid/tests/messaging/endpoints.py	2014-02-25 14:31:19.747965724 +0100
+++ qpid-0.14/python/qpid/tests/messaging/endpoints.py	2014-02-25 14:31:47.391622481 +0100
@@ -50,6 +50,10 @@ class SetupTests(Base):
     self.conn = Connection.establish(self.broker, tcp_nodelay=True)
     assert self.conn._driver._transport.socket.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
 
+  def testTcpKeepalive(self):
+    self.conn = Connection.establish(self.broker, tcp_keepalive=True)
+    assert self.conn._driver._transport.socket.getsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE)
+
   def testConnectError(self):
     try:
       # Specifying port 0 yields a bad address on Windows; port 4 is unassigned

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to