Reputation: 140
When I use the following code for a request to a FTP server. If the request failed I get an error. I don't know why.
Code:
try
{
FtpWebRequest request = GetFtpWebResquest(WebRequestMethods.Ftp.ListDirectoryDetails, shareInfo.Uri);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
root = new FtpResource(this, response);
}
catch (Exception e)
{
}
Exception:
Unhandled Exception:
System.Net.WebException: Request aborted
at System.Net.FtpWebRequest.CheckIfAborted () [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.set_State (RequestState value) [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.ProcessRequest () [0x00000] in <filename unknown>:0
at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.Net.WebException: Request aborted
at System.Net.FtpWebRequest.CheckIfAborted () [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.set_State (RequestState value) [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.ProcessRequest () [0x00000] in <filename unknown>:0
at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
@@@ ABORTING: INVALID HEAP ADDRESS IN dlfree addr=0x420e3580
_wapi_handle_ref: Attempting to ref unused handle 0x41c
* Assertion at /Users/builder/data/lanes/monodroid-lion-bs1/03814ac5/source/mono/mono/io-layer/wthreads.c:1365, condition `ok' not met
EDIT : For a better understanding I implemenent a simple test method called from an AsyncTask. The AsnycTask is starting once and I don't use an other thread except the GUI thread and this AsyncTask. In intervals of a few seconds the AsyncTask receives all entries of my ListView and set the state (offline/online). After 2 - 3 minutes I get the unhandled exception above.
AsynTask:
#region implemented abstract members of AsyncTask
protected override Java.Lang.Object DoInBackground (params Java.Lang.Object[] @params)
{
try
{
_isRunning = true;
while (_isRunning)
{
if (Statics.IsInternetAvailable(_context))
{
AvailableShareAdapter adapter = _context.GetAvailableSharesAdapter();
if (adapter != null)
{
List<ShareInformation> list = adapter.GetAllItems();
foreach(ShareInformation si in list)
{
if (!_isRunning)
break;
si.State = ShareInformation.ShareState.Testing;
_handler.Post(new Java.Lang.Runnable(() => { _context.GetAvailableSharesAdapter().NotifyDataSetChanged(); } ));
if (_coreFacade.SimpleTest(si.Uri, si.UserName, si.Password))
si.State = ShareInformation.ShareState.Online;
else
si.State = ShareInformation.ShareState.Offline;
_handler.Post(new Java.Lang.Runnable(() => { _context.GetAvailableSharesAdapter().NotifyDataSetChanged(); } ));
}
}
Thread.Sleep(60000);
}
}
} catch(Exception e)
{
_coreFacade.Log("DoInBackground", e.ToString());
}
return null;
}
#endregion
SimpleTest :
public bool SimpleTest(string uri, string username, string password)
{
Console.WriteLine("SimpleTest called");
try {
WebRequest request = HttpWebRequest.Create(uri);
request.Credentials = new NetworkCredential(username, password);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.Timeout = 30 * 1000;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
return true;
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
return false;
}
}
EDIT 2 : By the way...I only get this unhandled exception when the connection failed. If the FTP source available all works fine.
Upvotes: 4
Views: 1400
Reputation: 91
Short answer: it's a Mono bug (one of several in FtpWebRequest, actually). Switch to alternative FTP client class/libary (such as J.P. Trosclair's System.Net.FtpClient), if possible.
Long answer:
The thread that throws "Request aborted" exception is a runtime-created thread that's why you can't catch the exception (and why the runtime terminates).
I've run into same issue recently and spent quite some time debugging it.
If you look at Mono's FtpWebRequest (latest source as of now):
you'll see that ProcessRequest (from your stack trace) is a ThreadStart delegate and that the thread of interest is indeed created by the runtime (lines 391 and 442).
It turns out that FtpWebReuqest.GetResponse(), while synchronous per specification, is actually asynchronous under the hood [sic!] -- line 422. This creates dynamic environment which is (as we'll shortly see) error-prone.
Here's what happens in one of failing scenarios (TCP connect() timeout):
[calling thread] Create(); // FtpWebRequest object, State == RequestState.Before
[calling thread] GetResponse();
[calling thread] BeginGetResponse();
[calling thread] State = RequestState.Scheduled;
[calling thread] new Thread(ProcessRequest()).Start() // runtime-created thread
[calling thread] EndGetResponse();
[calling thread] WaitUntilComplete();
[runtime thread] ProcessRequest();
[runtime thread] ProcessMethod();
[runtime thread] State = RequestState.Connecting;
[runtime thread] OpenControlConnection();
[runtime thread] Socket.Connect();
<time passes>
[calling thread] Abort(); // WaitUntilComplete() times out
[calling thread] State = RequestState.Aborted; // [!!]
[calling thread] throw WebException("Transfer timed out");
// calling thread seems to think everything's fine, but...
<some time later>
[runtime thread] throw SocketException // Socket.Connect() times out
[runtime thread] sock = null; // from exception handler
[runtime thread] throw WebException("unable to connect to remote server");
// because sock was set to null
[runtime thread] State = RequestState.Error;
// exception is caught in ProcessRequest, an attempt is made to
// change the State to RequestState.Error, but it's already been
// set to RequestState.Aborted by the calling thread [!!]
[runtime thread] throw WebException("Request aborted");
// and this exception isn't caught anywhere... *KABOOM*
Aaaand that's how it happens. Unfortunately, the fix belongs in Mono.
You sure could try to work around it by setting a timeout that exceeds connect() timeout of the underlying socket but the truth is that there are few other code paths where Mono can throw exceptions that don't get handled... :-(
Upvotes: 4