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:
parent
ff5f9fa0c7
commit
d538bf0086
2 changed files with 38 additions and 6 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue