[geary/wip/actually-imap-logout: 5/5] Log out IMAP connections when stopping Imap.ClientService cleanly
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/actually-imap-logout: 5/5] Log out IMAP connections when stopping Imap.ClientService cleanly
- Date: Sun, 10 Feb 2019 03:48:51 +0000 (UTC)
commit 970f7b31d5d9939343abecd015126c9869b29429
Author: Michael Gratton <mike vee net>
Date: Thu Feb 7 14:08:50 2019 +1100
Log out IMAP connections when stopping Imap.ClientService cleanly
When closing the a session cleanly (i.e. since the service is being
stopped or a session is no longer needed, issue a logout instead of
simply terminating the connection. Use a second cancellable for
terminating logouts however when closing so we don't hang.
src/engine/imap/api/imap-client-service.vala | 78 +++++++++++++++++++++-------
1 file changed, 60 insertions(+), 18 deletions(-)
---
diff --git a/src/engine/imap/api/imap-client-service.vala b/src/engine/imap/api/imap-client-service.vala
index ff854815..0e46b089 100644
--- a/src/engine/imap/api/imap-client-service.vala
+++ b/src/engine/imap/api/imap-client-service.vala
@@ -89,7 +89,8 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
private Nonblocking.Queue<ClientSession> free_queue =
new Nonblocking.Queue<ClientSession>.fifo();
- private Cancellable? pool_cancellable = null;
+ private GLib.Cancellable? pool_cancellable = null;
+ private GLib.Cancellable? close_cancellable = null;
public ClientService(AccountInformation account,
@@ -109,7 +110,8 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
);
}
- this.pool_cancellable = new Cancellable();
+ this.pool_cancellable = new GLib.Cancellable();
+ this.close_cancellable = new GLib.Cancellable();
notify_started();
}
@@ -125,7 +127,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
notify_stopped();
this.pool_cancellable.cancel();
- yield close_pool();
+ yield close_pool(true);
// TODO: This isn't the best (deterministic) way to deal with
// this, but it's easy and works for now
@@ -140,6 +142,12 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
if (++attempts > 12)
break;
}
+
+ if (this.all_sessions.size > 0) {
+ debug("[%s] Cancelling remaining client sessions...",
+ this.account.id);
+ this.close_cancellable.cancel();
+ }
}
/**
@@ -217,7 +225,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
);
if (!this.is_running || this.discard_returned_sessions || too_many_free) {
- yield force_disconnect(session);
+ yield disconnect_session(session);
} else if (yield check_session(session, false)) {
bool free = true;
MailboxSpecifier? mailbox = null;
@@ -228,18 +236,30 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
proto == ClientSession.ProtocolState.SELECTING) {
// always close mailbox to return to authorized state
try {
- yield session.close_mailbox_async(pool_cancellable);
+ yield session.close_mailbox_async(this.close_cancellable);
} catch (ImapError imap_error) {
debug("[%s] Error attempting to close released session %s: %s",
this.account.id, session.to_string(), imap_error.message);
free = false;
}
- if (session.get_protocol_state(null) !=
- ClientSession.ProtocolState.AUTHORIZED) {
- // Closing it didn't work, so drop it
- yield force_disconnect(session);
+ // Double check the session after closing it
+ switch (session.get_protocol_state(null)) {
+ case AUTHORIZED:
+ // This is the desired state, so all good
+ break;
+
+ case UNCONNECTED:
+ // No longer connected, so just drop it
free = false;
+ break;
+
+ default:
+ // Closing it didn't leave it in the desired
+ // state, so log out and drop it
+ yield disconnect_session(session);
+ free = false;
+ break;
}
}
@@ -258,7 +278,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
/** Closes the client session pool. */
protected override void became_unreachable() {
- this.close_pool.begin();
+ this.close_pool.begin(false);
}
private async void check_pool(bool is_claiming) {
@@ -303,7 +323,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
if (new_session == null) {
// An error was thrown, so close the pool
- this.close_pool.begin();
+ this.close_pool.begin(true);
} else {
try {
yield this.sessions_mutex.execute_locked(() => {
@@ -317,7 +337,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
this.account.id, context.format_full_error());
notify_connection_failed(context);
new_session.disconnect_async.begin(null);
- this.close_pool.begin();
+ this.close_pool.begin(true);
}
}
}
@@ -334,7 +354,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
case ClientSession.ProtocolState.SELECTED:
case ClientSession.ProtocolState.SELECTING:
if (claiming) {
- yield force_disconnect(target);
+ yield disconnect_session(target);
} else {
valid = true;
}
@@ -351,7 +371,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
break;
default:
- yield force_disconnect(target);
+ yield disconnect_session(target);
break;
}
@@ -372,7 +392,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
try {
debug("Sending NOOP when claiming a session");
yield target.send_command_async(
- new NoopCommand(), this.pool_cancellable
+ new NoopCommand(), this.close_cancellable
);
} catch (Error err) {
debug("Error sending NOOP: %s", err.message);
@@ -416,7 +436,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
return new_session;
}
- private async void close_pool() {
+ private async void close_pool(bool clean_disconnect) {
debug("Closing the pool, disconnecting %d sessions",
this.all_sessions.size);
@@ -436,11 +456,33 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
// waiting for any since we don't want to delay closing the
// others.
foreach (ClientSession session in to_close) {
- session.disconnect_async.begin();
+ if (clean_disconnect) {
+ this.disconnect_session.begin(session);
+ } else {
+ this.force_disconnect_session.begin(session);
+ }
}
}
- private async void force_disconnect(ClientSession session) {
+ private async void disconnect_session(ClientSession session) {
+ debug("[%s] Logging out session %s",
+ this.account.id, session.to_string());
+
+ // Log out before removing the session since close() only
+ // hangs around until all sessions have been removed before
+ // exiting.
+ try {
+ yield session.logout_async(this.close_cancellable);
+ yield remove_session_async(session);
+ } catch (GLib.Error err) {
+ debug("[%s] Error logging out of session: %s",
+ this.account.id, err.message);
+ yield force_disconnect_session(session);
+ }
+
+ }
+
+ private async void force_disconnect_session(ClientSession session) {
debug("[%s] Dropping session %s", this.account.id, session.to_string());
try {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]