Skip to content

The server committed a protocol violation #82

@twodogmbh

Description

@twodogmbh

When multiple connections are opened in parallel, the client terminates with the following exception:

System.Net.WebException: The underlying connection was closed: The server committed a protocol violation.
 at System.Net.FtpWebRequest.DataStreamClosed(CloseExState closeState)
at System.Net.FtpDataStream.System.Net.ICloseEx.CloseEx(CloseExState closeState)
at System.Net.FtpDataStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.Net.FtpDataStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.IO.StreamReader.ReadBuffer()
at System.IO.StreamReader.ReadLine()

This occurs with the default FTP server configuration as described in the example: https://github.com/FubarDevelopment/FtpServer

The issue can be reproduced with the following test:

    [TestMethod]
    public async Task GetFilesInParallel()
    {
        var tasks = new List<Task>();
        for(var i = 0; i < 100; i++)
        {
            var task = Task.Run(this.GetFilesAsync);
            tasks.Add(task);
        }

        await Task.WhenAll(tasks).ConfigureAwait(false);
    }

    private async Task<IList<string>> GetFilesAsync()
    {
        var requestUri = "ftp://localhost";
        var request = (FtpWebRequest)WebRequest.Create(requestUri);
        request.Method = WebRequestMethods.Ftp.ListDirectory;
        request.Credentials = new NetworkCredential("anonymous", "foo@bar.com");
        request.KeepAlive = false;

        var files = new List<string>();
        using (var response = await request.GetResponseAsync().ConfigureAwait(false))
        {
            using (var responseStream = response.GetResponseStream())
            {
                using (var reader = new StreamReader(responseStream))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        files.Add(Path.GetFileName(line));
                    }

                    reader.Close();
                    responseStream.Close();
                }
            }
        }

        return files;
    }

When the KeepAlive property is set to "true" the test passes.

It seems like, when the connection is closed, the server terminates the connection too fast, before the response is sent.

For the ListDirectory command it's not a big issue, as we could just re-try, but for the DeleteFile command it's not that easy as the second re-try then returns error code 503.

The response.StatusProperty contains "250 Closing data connection."

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions