From 1cf0799021c02576f41be716c47b9d3bccd20b11 Mon Sep 17 00:00:00 2001 From: Vsevolod Parfenov Date: Thu, 17 Jan 2013 13:34:11 +0600 Subject: [PATCH 1/4] Cancel accepting passive connection after 20 seconds --- Source/RemObjects.InternetPack/Bindings.cs | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Source/RemObjects.InternetPack/Bindings.cs b/Source/RemObjects.InternetPack/Bindings.cs index 801df4a..bd9fc37 100644 --- a/Source/RemObjects.InternetPack/Bindings.cs +++ b/Source/RemObjects.InternetPack/Bindings.cs @@ -131,6 +131,8 @@ public Boolean ShouldSerializePort() public class ServerBinding : Binding { + ManualResetEvent _accepted; + public ServerBinding() { this.fListenerThreadCount = 1; @@ -254,7 +256,27 @@ public virtual void BindUnthreaded() public virtual Connection Accept() { - return new Connection(this.fListeningSocket.Accept()); + using (_accepted = new ManualResetEvent(false)) + { + var cancelThread = new Thread(CancelAccept); + cancelThread.Start(); + + var socket = this.fListeningSocket.Accept(); + + _accepted.Set(); + cancelThread.Join(); + _accepted = null; + + return new Connection(socket); + } + } + + void CancelAccept() + { + if (_accepted.WaitOne(TimeSpan.FromSeconds(20))) + return; + + fListeningSocket.Close(); } } From 8329ca82d9ac0f3287ca68123302232281836c0e Mon Sep 17 00:00:00 2001 From: Vsevolod Parfenov Date: Thu, 17 Jan 2013 13:44:34 +0600 Subject: [PATCH 2/4] Better resource handling --- Source/RemObjects.InternetPack/Bindings.cs | 27 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Source/RemObjects.InternetPack/Bindings.cs b/Source/RemObjects.InternetPack/Bindings.cs index bd9fc37..e8e887f 100644 --- a/Source/RemObjects.InternetPack/Bindings.cs +++ b/Source/RemObjects.InternetPack/Bindings.cs @@ -237,12 +237,16 @@ public virtual void Unbind(Boolean block) if (this.fListeningSocket == null) return; - this.fListeningSocket.Close(); + using (this.fListeningSocket) + { + this.fListeningSocket.Close(); #if FULLFRAMEWORK - if (block && this.fListenThreads != null) - for (Int32 i = 0; i < this.fListenThreads.Length; i++) - this.fListenThreads[i].Join(); + if (block && this.fListenThreads != null) + for (Int32 i = 0; i < this.fListenThreads.Length; i++) + this.fListenThreads[i].Join(); #endif + this.fListeningSocket = null; + } } public virtual void BindUnthreaded() @@ -251,7 +255,20 @@ public virtual void BindUnthreaded() this.fListeningSocket = new Socket(this.AddressFamily, this.SocketType, this.Protocol); if (!this.EnableNagle) this.fListeningSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 1); - this.fListeningSocket.Bind(this.fEndPoint); + + try + { + this.fListeningSocket.Bind(this.fEndPoint); + } + catch (SocketException) + { + using (this.fListeningSocket) + { + this.fListeningSocket = null; + } + this.fEndPoint = null; + throw; + } } public virtual Connection Accept() From 9ccec141ad9290a6988ca3a9e7a838f6a8f84aa3 Mon Sep 17 00:00:00 2001 From: Vsevolod Parfenov Date: Thu, 17 Jan 2013 14:07:13 +0600 Subject: [PATCH 3/4] Explicit port range for passive connections --- Source/RemObjects.InternetPack/FtpServer.cs | 6 +- .../RemObjects.InternetPack/SimpleServer.cs | 57 ++++++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/Source/RemObjects.InternetPack/FtpServer.cs b/Source/RemObjects.InternetPack/FtpServer.cs index 0908639..73530ed 100644 --- a/Source/RemObjects.InternetPack/FtpServer.cs +++ b/Source/RemObjects.InternetPack/FtpServer.cs @@ -1161,7 +1161,11 @@ public static void Cmd_PASV(Object sender, CommandEventArgs e) lSession.PassiveServer = new SimpleServer(); lSession.PassiveServer.Binding.Address = ((IPEndPoint)e.Connection.LocalEndPoint).Address; - lSession.PassiveServer.Open(); + if (!lSession.PassiveServer.Open()) + { + e.Connection.WriteLine("421 Can't create socket"); + return; + } } lSession.Passive = true; diff --git a/Source/RemObjects.InternetPack/SimpleServer.cs b/Source/RemObjects.InternetPack/SimpleServer.cs index 84cbcf7..d8c16d0 100644 --- a/Source/RemObjects.InternetPack/SimpleServer.cs +++ b/Source/RemObjects.InternetPack/SimpleServer.cs @@ -6,12 +6,16 @@ Using this code requires a valid license of the RemObjects Internet Pack which can be obtained at http://www.remobjects.com?ip. ---------------------------------------------------------------------------*/ +using System; using System.Net; +using System.Net.Sockets; +using System.Runtime.CompilerServices; namespace RemObjects.InternetPack { public class SimpleServer { + public static readonly SimplePortPool Pool = new SimplePortPool(); public SimpleServer() { this.fBinding = new ServerBinding(); @@ -29,10 +33,27 @@ public ServerBinding Binding private ServerBinding fBinding; #endregion - public void Open() + public bool Open() { - this.Binding.BindUnthreaded(); - this.Binding.ListeningSocket.Listen(this.Binding.MaxWaitConnections); + var retries = 3; + while (retries > 0) + { + try + { + this.Binding.Port = Pool.GetNextSocketPort(); + this.Binding.BindUnthreaded(); + this.Binding.ListeningSocket.Listen(this.Binding.MaxWaitConnections); + break; + } + catch (SocketException) + { + this.Binding.Unbind(); + } + + --retries; + } + + return retries > 0; } public void Close() @@ -45,4 +66,34 @@ public Connection WaitForConnection() return this.Binding.Accept(); } } + + public class SimplePortPool + { + int _minPort = 5000; + int _maxPort = 5010; + int _nextPort; + + public void SetPortRange(int min, int max) + { + if (min >= max) + throw new InvalidOperationException(); + + _minPort = min; + _maxPort = max; + + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public int GetNextSocketPort() + { + if (_minPort > _maxPort) + throw new InvalidOperationException("Max port should be greater than min port"); + + if (_nextPort < _minPort || _maxPort < _nextPort) + _nextPort = _minPort; + var port = _nextPort; + ++_nextPort; + return port; + } + } } \ No newline at end of file From 4089a1d8e15b25f641acb6f128fbd14b85c96c35 Mon Sep 17 00:00:00 2001 From: Vsevolod Parfenov Date: Thu, 17 Jan 2013 14:21:50 +0600 Subject: [PATCH 4/4] Mechanism to override server IP address --- Source/RemObjects.InternetPack/FtpServer.cs | 4 ++-- Source/RemObjects.InternetPack/SimpleServer.cs | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Source/RemObjects.InternetPack/FtpServer.cs b/Source/RemObjects.InternetPack/FtpServer.cs index 73530ed..42ea5ed 100644 --- a/Source/RemObjects.InternetPack/FtpServer.cs +++ b/Source/RemObjects.InternetPack/FtpServer.cs @@ -1171,10 +1171,10 @@ public static void Cmd_PASV(Object sender, CommandEventArgs e) Byte[] lAddress; #if FULLFRAMEWORK - lAddress = ((IPEndPoint)lSession.PassiveServer.Binding.ListeningSocket.LocalEndPoint).Address.GetAddressBytes(); + lAddress = lSession.PassiveServer.GetLocalEndpointAddress().GetAddressBytes(); #endif #if COMPACTFRAMEWORK - IPAddress lIPAddress = ((IPEndPoint)lSession.PassiveServer.Binding.ListeningSocket.LocalEndPoint).Address; + IPAddress lIPAddress = lSession.PassiveServer.GetLocalEndpointAddress(); String[] lIPAddressstr = lIPAddress.ToString().Split(new Char[] {'.'}); lAddress = new Byte[lIPAddressstr.Length]; for (Int32 i = 0; i < lIPAddressstr.Length; i++) diff --git a/Source/RemObjects.InternetPack/SimpleServer.cs b/Source/RemObjects.InternetPack/SimpleServer.cs index d8c16d0..6f71df7 100644 --- a/Source/RemObjects.InternetPack/SimpleServer.cs +++ b/Source/RemObjects.InternetPack/SimpleServer.cs @@ -16,6 +16,7 @@ namespace RemObjects.InternetPack public class SimpleServer { public static readonly SimplePortPool Pool = new SimplePortPool(); + public static IPAddress LocalEndpointIpAddress; public SimpleServer() { this.fBinding = new ServerBinding(); @@ -65,6 +66,16 @@ public Connection WaitForConnection() { return this.Binding.Accept(); } + + public IPAddress GetLocalEndpointAddress() + { + return LocalEndpointIpAddress ?? ((IPEndPoint)Binding.ListeningSocket.LocalEndPoint).Address; + } + + public Int32 GetLocalEndpointPort() + { + return ((IPEndPoint) Binding.ListeningSocket.LocalEndPoint).Port; + } } public class SimplePortPool