private async Task ProcessMessages()
{
Log?.Info($"Connected from {RemoteAddress.ToString(true)}");
using (var collector = new FtpCommandCollector(() => Encoding))
{
await WriteAsync(new FtpResponse(220, "FTP Server Ready"), _cancellationTokenSource.Token);
var buffer = new byte[1024];
try
{
Task<int> readTask = null;
for (; ;)
{
if (readTask == null)
readTask = SocketStream.ReadAsync(buffer, 0, buffer.Length, _cancellationTokenSource.Token);
var tasks = new List<Task>() { readTask };
if (_activeBackgroundTask != null)
tasks.Add(_activeBackgroundTask);
Debug.WriteLine($"Waiting for {tasks.Count} tasks");
var completedTask = Task.WaitAny(tasks.ToArray(), _cancellationTokenSource.Token);
Debug.WriteLine($"Task {completedTask} completed");
if (completedTask == 1)
{
var response = _activeBackgroundTask?.Result;
if (response != null)
Write(response);
_activeBackgroundTask = null;
}
else
{
var bytesRead = readTask.Result;
readTask = null;
if (bytesRead == 0)
break;
var commands = collector.Collect(buffer, 0, bytesRead);
foreach (var command in commands)
{
await ProcessMessage(command);
}
}
}
}
catch (OperationCanceledException)
{
// Ignore the OperationCanceledException
// This is normal during disconnects
}
catch (Exception ex)
{
Log?.Error(ex, "Failed to process connection");
}
finally
{
Log?.Info($"Disconnection from {RemoteAddress.ToString(true)}");
_closed = true;
Data.BackgroundCommandHandler.Cancel();
if (!ReferenceEquals(SocketStream, OriginalStream))
{
SocketStream.Dispose();
SocketStream = OriginalStream;
}
_socket.Dispose();
OnClosed();
}
}
}