Crash when navigating quickly between folders: Closes #6277

This has been a problem in the past, and it usually has to do with
shutting down the ClientSession or ClientConnection while connecting.
That is true here too.  (In this case, it's due to the request being
cancelled while connecting.)  This uses the ClientSession's FSM's to
better deal with the case and move the ClientSession to a BROKEN
state where it belongs.  There's also some code in ClientConnection
to ensure that if connect_async() fails, no resource leaks occur.
This commit is contained in:
Jim Nelson 2013-01-29 14:14:58 -08:00
parent ff5f9fa0c7
commit d538bf0086
2 changed files with 38 additions and 6 deletions

View file

@ -297,7 +297,7 @@ public class Geary.Imap.ClientConnection {
*/
public async void connect_async(Cancellable? cancellable = null) throws Error {
if (cx != null) {
debug("Already connected to %s", to_string());
debug("Already connected/connecting to %s", to_string());
return;
}
@ -305,11 +305,30 @@ public class Geary.Imap.ClientConnection {
cx = yield endpoint.connect_async(cancellable);
ios = cx;
// issue CONNECTED event and fire signal because the moment the channels are hooked up,
// data can start flowing
fsm.issue(Event.CONNECTED);
connected();
yield open_channels_async(cancellable);
try {
yield open_channels_async();
} catch (Error err) {
// if this fails, need to close connection because the caller will not call
// disconnect_async()
try {
yield cx.close_async();
} catch (Error close_err) {
// ignored
}
fsm.issue(Event.DISCONNECTED);
cx = null;
ios = null;
throw err;
}
}
public async void disconnect_async(Cancellable? cancellable = null) throws Error {
@ -349,7 +368,7 @@ public class Geary.Imap.ClientConnection {
}
}
private async void open_channels_async(Cancellable? cancellable) throws Error {
private async void open_channels_async() throws Error {
assert(ios != null);
assert(ser == null);
assert(des == null);
@ -407,7 +426,7 @@ public class Geary.Imap.ClientConnection {
ios = tls_cx;
// re-open Serializer/Deserializer with the new streams
yield open_channels_async(cancellable);
yield open_channels_async();
}
private void on_parameters_ready(RootParameters root) {

View file

@ -265,8 +265,8 @@ public class Geary.Imap.ClientSession {
new Geary.State.Mapping(State.CONNECTING, Event.DISCONNECT, on_disconnect),
new Geary.State.Mapping(State.CONNECTING, Event.CONNECTED, on_connected),
new Geary.State.Mapping(State.CONNECTING, Event.CONNECT_DENIED, on_connect_denied),
new Geary.State.Mapping(State.CONNECTING, Event.SEND_ERROR, on_send_error),
new Geary.State.Mapping(State.CONNECTING, Event.RECV_ERROR, on_recv_error),
new Geary.State.Mapping(State.CONNECTING, Event.SEND_ERROR, on_connecting_send_recv_error),
new Geary.State.Mapping(State.CONNECTING, Event.RECV_ERROR, on_connecting_send_recv_error),
new Geary.State.Mapping(State.NOAUTH, Event.LOGIN, on_login),
new Geary.State.Mapping(State.NOAUTH, Event.SEND_CMD, on_send_command),
@ -1153,6 +1153,19 @@ public class Geary.Imap.ClientSession {
// error handling
//
// use different error handler when connecting because, if connect_async() fails, there's no
// requirement for the user to call disconnect_async() and cleaning up... this prevents leaving the
// FSM in the CONNECTING state, causing an assertion when this object is destroyed
private uint on_connecting_send_recv_error(uint state, uint event, void *user, Object? object, Error? err) {
assert(err != null);
debug("[%s] Connecting send error, dropping client connection: %s", to_full_string(), err.message);
fsm.do_post_transition(() => { drop_connection(); });
return State.BROKEN;
}
private uint on_send_error(uint state, uint event, void *user, Object? object, Error? err) {
assert(err != null);