From af814fb3413c1817a39050d0f8367ebeb115334e Mon Sep 17 00:00:00 2001 From: Jan Klass Date: Tue, 29 Apr 2025 17:19:27 +0200 Subject: [PATCH] fix: Ignore remote peer aborts when accepting clients Fixes FTP server becoming unresponsive due to stopped listeners. --- A socket may throw SocketException. This may occur as early as AcceptTcpClientAsync during initial connect hand-shake. With this change, a socket exception with the error code 10054 is ignored during client accept. We do not want to stop the listener altogether when a new client closes their connection. That must only close the client connection. Socket error code 10054: WSAECONNRESET, SocketError.ConnectionReset, 'The connection was reset by the remote peer.' * https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2 * https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socketerror https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcplistener.accepttcpclientasync --- The issue is reproducible in a test scenario of generating mass-connects (my tests had 20 times sets of 400 started concurrently as Tasks). The server will consistently become unresponsive (as in, no longer handle new connection requests but still run as a service as if nothing were wrong) after a few hundred connections and connection closings. I have seen the issue multiple times in production too. Co-authored-by: Jan Klass --- src/FubarDev.FtpServer/MultiBindingTcpListener.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/FubarDev.FtpServer/MultiBindingTcpListener.cs b/src/FubarDev.FtpServer/MultiBindingTcpListener.cs index 208cc137..587ab626 100644 --- a/src/FubarDev.FtpServer/MultiBindingTcpListener.cs +++ b/src/FubarDev.FtpServer/MultiBindingTcpListener.cs @@ -184,6 +184,11 @@ private async Task AcceptForListenerAsync(TcpListener listener, int // Ignore the exception. This happens when the listener gets stopped. return new AcceptInfo(null, index); } + catch (SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionReset) + { + // The remote peer closed the connection during the handshake process. We ignore these. + return new AcceptInfo(null, index); + } } private int StartListening(IEnumerable addresses, int port)