private void AsyncRequestCallback(object obj)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(this, obj);
RequestStage stageMode = RequestStage.CheckForError;
try
{
FtpControlStream connection;
connection = obj as FtpControlStream;
FtpDataStream stream = obj as FtpDataStream;
Exception exception = obj as Exception;
bool completedRequest = (obj == null);
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"stream:{stream} conn:{connection} exp:{exception} completedRequest:{completedRequest}");
while (true)
{
if (exception != null)
{
if (AttemptedRecovery(exception))
{
connection = CreateConnection();
if (connection == null)
return;
exception = null;
}
if (exception != null)
{
SetException(exception);
break;
}
}
if (connection != null)
{
lock (_syncObject)
{
if (_aborted)
{
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Releasing connect:{connection}");
connection.CloseSocket();
break;
}
_connection = connection;
if (NetEventSource.IsEnabled) NetEventSource.Associate(this, _connection);
}
try
{
stream = (FtpDataStream)TimedSubmitRequestHelper(true);
}
catch (Exception e)
{
exception = e;
continue;
}
return;
}
else if (stream != null)
{
lock (_syncObject)
{
if (_aborted)
{
((ICloseEx)stream).CloseEx(CloseExState.Abort | CloseExState.Silent);
break;
}
_stream = stream;
}
stream.SetSocketTimeoutOption(Timeout);
EnsureFtpWebResponse(null);
stageMode = stream.CanRead ? RequestStage.ReadReady : RequestStage.WriteReady;
}
else if (completedRequest)
{
connection = _connection;
if (connection != null)
{
EnsureFtpWebResponse(null);
// This to update response status and exit message if any.
// Note that the status 221 "Service closing control connection" is always suppressed.
_ftpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage);
}
stageMode = RequestStage.ReleaseConnection;
}
else
{
throw new InternalException();
}
break;
}
}
catch (Exception exception)
{
SetException(exception);
}
finally
{
FinishRequestStage(stageMode);
if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
}
}