Merge pull request #38 from Havret/add_tcp_keep_alive_support

AMQNET-616: Add TCP Keep-Alive support
diff --git a/docs/configuration.md b/docs/configuration.md
index 1c4d1e0..2b3046e 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -37,8 +37,12 @@
 - **transport.receiveBufferSize** Specifies the SendBufferSize option of the TCP socket.
 - **transport.receiveTimeout** Specifies the ReceiveTimeout option of the TCP socket.
 - **transport.sendTimeout** Specifies the SendTimeout option of the TCP socket.
+- **transport.tcpKeepAliveTime** Specifies how often a keep-alive transmission is sent to an idle connection.
+- **transport.tcpKeepAliveInterval** Specifies how often a keep-alive transmission is sent when no response is received from previous keep-alive transmissions.
 - **transport.tcpNoDelay** Specifies the NoDelay option of the TCP socket.
 
+If *tcpKeepAliveTime* or *tcpKeepAliveInterval* it set, TCP Keep-Alive is enabled.
+
 ### Failover Configuration options
 With failover enabled the client can reconnect to another server automatically when connection to the current server is lost for some reason. The failover URI is always initiated with the failover prefix and a list of URIs for the server(s) is contained inside a set of parentheses. The "nms." options are applied to the overall failover URI, outside the parentheses, and affect the NMS Connection object for its lifetime.
 
diff --git a/src/NMS.AMQP/Transport/ISecureTransportContext.cs b/src/NMS.AMQP/Transport/ISecureTransportContext.cs
index 4cac12e..97762dd 100644
--- a/src/NMS.AMQP/Transport/ISecureTransportContext.cs
+++ b/src/NMS.AMQP/Transport/ISecureTransportContext.cs
@@ -21,9 +21,6 @@
 {
     public interface ISecureTransportContext : ITransportContext
     {
-        
-        new ISecureTransportContext Copy();
-
         string ServerName { get; set; }
 
         string ClientCertFileName { get; set; }
diff --git a/src/NMS.AMQP/Transport/ITransportContext.cs b/src/NMS.AMQP/Transport/ITransportContext.cs
index a7afefb..05eec6e 100644
--- a/src/NMS.AMQP/Transport/ITransportContext.cs
+++ b/src/NMS.AMQP/Transport/ITransportContext.cs
@@ -33,11 +33,19 @@
         int SendTimeout { get; set; }
         
         bool TcpNoDelay { get; set; }
+
+        /// <summary>
+        /// Gets or sets how often a keep-alive transmission is sent to an idle connection.
+        /// </summary>
+        uint TcpKeepAliveTime { get; set; }
+        
+        /// <summary>
+        /// Gets or sets How often a keep-alive transmission is sent when no response is received from previous keep-alive transmissions.
+        /// </summary>
+        uint TcpKeepAliveInterval { get; set; }
         
         bool IsSecure { get; }
         
-        ITransportContext Copy();
-        
         Task<Connection> CreateAsync(Address address, IHandler handler);
     }
 }
diff --git a/src/NMS.AMQP/Transport/SecureTransportContext.cs b/src/NMS.AMQP/Transport/SecureTransportContext.cs
index cc3913c..08cfc66 100644
--- a/src/NMS.AMQP/Transport/SecureTransportContext.cs
+++ b/src/NMS.AMQP/Transport/SecureTransportContext.cs
@@ -37,8 +37,8 @@
     internal class SecureTransportContext : TransportContext, ISecureTransportContext
     {
         
-        private readonly static List<string> SupportedProtocols;
-        private readonly static Dictionary<string, int> SupportedProtocolValues;
+        private static readonly List<string> SupportedProtocols;
+        private static readonly Dictionary<string, int> SupportedProtocolValues;
 
         #region static Initializer
 
@@ -411,65 +411,6 @@
         }
 
         #endregion
-        
-        #region Copy Methods
-
-
-        protected override void CopyBuilder(Amqp.ConnectionFactory copy)
-        {
-            base.CopyBuilder(copy);
-            
-            copy.SSL.Protocols = connectionBuilder.SSL.Protocols;
-            copy.SSL.CheckCertificateRevocation = connectionBuilder.SSL.CheckCertificateRevocation;
-
-            if (connectionBuilder.SSL.ClientCertificates != null)
-            {
-                copy.SSL.ClientCertificates = new X509CertificateCollection(connectionBuilder.SSL.ClientCertificates);
-            }
-
-        }
-
-        protected override void CopyInto(TransportContext copy)
-        {
-            SecureTransportContext stcCopy = copy as SecureTransportContext;
-
-            // Copy Secure properties.
-
-            // copy keystore properties
-            stcCopy.KeyStoreName = this.KeyStoreName;
-            stcCopy.KeyStorePassword = this.KeyStorePassword;
-            stcCopy.KeyStoreLocation = this.KeyStoreLocation;
-
-            // copy certificate properties
-            stcCopy.AcceptInvalidBrokerCert = this.AcceptInvalidBrokerCert;
-            stcCopy.ServerName = this.ServerName;
-            stcCopy.ClientCertFileName = this.ClientCertFileName;
-            stcCopy.ClientCertPassword = this.ClientCertPassword;
-            stcCopy.ClientCertSubject = this.ClientCertSubject;
-
-            // copy application callback
-            stcCopy.ServerCertificateValidateCallback = this.ServerCertificateValidateCallback;
-            stcCopy.ClientCertificateSelectCallback = this.ClientCertificateSelectCallback;
-            
-            base.CopyInto(copy);
-
-            stcCopy.connectionBuilder.SSL.RemoteCertificateValidationCallback = this.ContextServerCertificateValidation;
-            stcCopy.connectionBuilder.SSL.LocalCertificateSelectionCallback = this.ContextLocalCertificateSelect;
-        }
-
-        public override ITransportContext Copy()
-        {
-            TransportContext copy = new SecureTransportContext();
-            this.CopyInto(copy);
-            return copy;
-        }
-        
-        ISecureTransportContext ISecureTransportContext.Copy()
-        {
-            return this.Copy() as SecureTransportContext;
-        }
-
-        #endregion
     }
 
 }
diff --git a/src/NMS.AMQP/Transport/TransportContext.cs b/src/NMS.AMQP/Transport/TransportContext.cs
index d5aead9..e62c9ac 100644
--- a/src/NMS.AMQP/Transport/TransportContext.cs
+++ b/src/NMS.AMQP/Transport/TransportContext.cs
@@ -26,9 +26,6 @@
 
 namespace Apache.NMS.AMQP.Transport
 {
-
-    #region Transport Context
-
     /// <summary>
     /// Transport management is mainly handled by the AmqpNetLite library, Except for custom transports.
     /// TransportContext should configure the Amqp.ConnectionFactory for the tcp transport properties.
@@ -43,15 +40,25 @@
             connectionBuilder.SASL.Profile = Amqp.Sasl.SaslProfile.Anonymous;            
         }
 
-        #region Transport Options
-
         public int ReceiveBufferSize { get => this.connectionBuilder.TCP.ReceiveBufferSize; set => this.connectionBuilder.TCP.ReceiveBufferSize = value; }
         public int ReceiveTimeout { get => this.connectionBuilder.TCP.ReceiveTimeout; set => this.connectionBuilder.TCP.ReceiveTimeout = value; }
         public int SendBufferSize { get => this.connectionBuilder.TCP.SendBufferSize; set => this.connectionBuilder.TCP.SendBufferSize = value; }
         public int SendTimeout { get => this.connectionBuilder.TCP.SendTimeout; set => this.connectionBuilder.TCP.SendTimeout = value; }
         public bool TcpNoDelay { get => this.connectionBuilder.TCP.NoDelay; set => this.connectionBuilder.TCP.NoDelay = value; }
-        public uint TcpKeepAliveTime { get => this.connectionBuilder.TCP.KeepAlive.KeepAliveTime; set => this.connectionBuilder.TCP.KeepAlive.KeepAliveTime = value; }
-        public uint TcpKeepAliveInterval { get => this.connectionBuilder.TCP.KeepAlive.KeepAliveInterval; set => this.connectionBuilder.TCP.KeepAlive.KeepAliveInterval = value; }
+
+        public uint TcpKeepAliveTime
+        {
+            get => this.connectionBuilder.TCP.KeepAlive?.KeepAliveTime ?? default;
+            set => this.TcpKeepAliveSettings.KeepAliveTime = value;
+        }
+
+        public uint TcpKeepAliveInterval
+        {
+            get => this.connectionBuilder.TCP.KeepAlive?.KeepAliveInterval ?? default;
+            set => this.TcpKeepAliveSettings.KeepAliveInterval = value;
+        }
+
+        private TcpKeepAliveSettings TcpKeepAliveSettings => this.connectionBuilder.TCP.KeepAlive ?? (this.connectionBuilder.TCP.KeepAlive = new TcpKeepAliveSettings());
 
         public bool SocketLingerEnabled
         {
@@ -84,42 +91,12 @@
                 }
             }
         }
-        
-        #endregion
 
         public virtual bool IsSecure { get; } = false;
 
-        public virtual ITransportContext Copy()
-        {
-            TransportContext copy = new TransportContext();
-            this.CopyInto(copy);
-            return copy;
-        }
-
         public virtual Task<Connection> CreateAsync(Address address, IHandler handler)
         {
             return connectionBuilder.CreateAsync(address, handler);    
         }
-
-        protected virtual void CopyInto(TransportContext copy)
-        {
-            //copy.factory = this.factory;
-            //copy.UseLogging = this.UseLogging;
-            //Amqp.ConnectionFactory builder = new Amqp.ConnectionFactory();
-            //this.CopyBuilder(builder);
-            //copy.connectionBuilder = builder;
-        }
-
-        protected virtual void CopyBuilder(Amqp.ConnectionFactory copy)
-        {
-            StringDictionary amqpProperties = PropertyUtil.GetProperties(this.connectionBuilder.AMQP);
-            StringDictionary tcpProperties = PropertyUtil.GetProperties(this.connectionBuilder.TCP);
-            PropertyUtil.SetProperties(copy.AMQP, amqpProperties);
-            PropertyUtil.SetProperties(copy.TCP, tcpProperties);
-            copy.SASL.Profile = this.connectionBuilder.SASL.Profile;
-        }
     }
-
-    #endregion
-
 }
diff --git a/test/Apache-NMS-AMQP-Test/Transport/TransportContextFactoryTest.cs b/test/Apache-NMS-AMQP-Test/Transport/TransportContextFactoryTest.cs
index 8669370..5e69210 100644
--- a/test/Apache-NMS-AMQP-Test/Transport/TransportContextFactoryTest.cs
+++ b/test/Apache-NMS-AMQP-Test/Transport/TransportContextFactoryTest.cs
@@ -29,6 +29,8 @@
         private int customReceiveTimeout = 1000;
         private int customSendBufferSize = 32 * 1024;
         private int customSendTimeout = 2000;
+        private int customTcpKeepAliveTime = 2500;
+        private int customTcpKeepAliveInterval = 3000;
 
         [Test]
         public void TestCreateWithDefaultOptions()
@@ -54,6 +56,8 @@
                               "transport.receiveTimeout=" + customReceiveTimeout + "&" +
                               "transport.sendBufferSize=" + customSendBufferSize + "&" +
                               "transport.sendTimeout=" + customSendTimeout + "&" +
+                              "transport.tcpKeepAliveTime=" + customTcpKeepAliveTime + "&" +
+                              "transport.tcpKeepAliveInterval=" + customTcpKeepAliveInterval + "&" +
                               "transport.tcpNoDelay=" + customTcpNoDelay);
             ITransportContext transportContext = TransportContextFactory.CreateTransportContext(uri);
 
@@ -64,6 +68,8 @@
             Assert.AreEqual(customReceiveTimeout, transportContext.ReceiveTimeout);
             Assert.AreEqual(customSendBufferSize, transportContext.SendBufferSize);
             Assert.AreEqual(customSendTimeout, transportContext.SendTimeout);
+            Assert.AreEqual(customTcpKeepAliveTime, transportContext.TcpKeepAliveTime);
+            Assert.AreEqual(customTcpKeepAliveInterval, transportContext.TcpKeepAliveInterval);
             Assert.AreEqual(customTcpNoDelay, transportContext.TcpNoDelay);
         }