[geary/wip/cx-reestablish] Use NetworkMonitor to determine if IMAP endpoint is reachable
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/cx-reestablish] Use NetworkMonitor to determine if IMAP endpoint is reachable
- Date: Fri, 23 Jan 2015 00:52:02 +0000 (UTC)
commit 528dec9ed7a79f614f011521829260eb107f52eb
Author: Jim Nelson <jim yorba org>
Date: Thu Jan 22 16:49:50 2015 -0800
Use NetworkMonitor to determine if IMAP endpoint is reachable
This prevents the ClientSessionManager from dumbly retrying
connections when the network is simply unavailable.
src/engine/imap/imap-error.vala | 4 +
.../transport/imap-client-session-manager.vala | 105 +++++++++++++++++---
2 files changed, 96 insertions(+), 13 deletions(-)
---
diff --git a/src/engine/imap/imap-error.vala b/src/engine/imap/imap-error.vala
index c88cc32..f9e4e32 100644
--- a/src/engine/imap/imap-error.vala
+++ b/src/engine/imap/imap-error.vala
@@ -52,5 +52,9 @@ public errordomain Geary.ImapError {
* This indicates a local time out, not one reported by the server.
*/
TIMED_OUT,
+ /**
+ * Network is unavailable.
+ */
+ UNAVAILABLE
}
diff --git a/src/engine/imap/transport/imap-client-session-manager.vala
b/src/engine/imap/transport/imap-client-session-manager.vala
index 9b1b363..c84ccce 100644
--- a/src/engine/imap/transport/imap-client-session-manager.vala
+++ b/src/engine/imap/transport/imap-client-session-manager.vala
@@ -45,7 +45,18 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
*/
public int min_pool_size { get; set; default = DEFAULT_MIN_POOL_SIZE; }
+ /**
+ * Indicates if the { link Endpoint} the { link ClientSessionManager} connects to is reachable,
+ * according to the NetworkMonitor.
+ *
+ * By default, this is true, optimistic the network is reachable. It is updated even if the
+ * { link ClientSessionManager} is not open, maintained for the lifetime of the object.
+ */
+ public bool is_endpoint_reachable { get; private set; default = true; }
+
private AccountInformation account_information;
+ private Endpoint endpoint;
+ private NetworkMonitor network_monitor;
private Gee.HashSet<ClientSession> sessions = new Gee.HashSet<ClientSession>();
private int pending_sessions = 0;
private Nonblocking.Mutex sessions_mutex = new Nonblocking.Mutex();
@@ -54,16 +65,27 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
private bool untrusted_host = false;
private uint authorized_session_error_retry_timeout_id = 0;
private int authorized_session_retry_sec = AUTHORIZED_SESSION_ERROR_MIN_RETRY_TIMEOUT_SEC;
+ private bool checking_reachable = false;
public signal void login_failed();
public ClientSessionManager(AccountInformation account_information) {
this.account_information = account_information;
+ // NOTE: This works because AccountInformation guarantees the IMAP endpoint not to change
+ // for the lifetime of the AccountInformation object; if this ever changes, will need to
+ // refactor for that
+ endpoint = account_information.get_imap_endpoint();
+ network_monitor = NetworkMonitor.get_default();
account_information.notify["imap-credentials"].connect(on_imap_credentials_notified);
- account_information.get_imap_endpoint().untrusted_host.connect(on_imap_untrusted_host);
- account_information.get_imap_endpoint().notify[Endpoint.PROP_TRUST_UNTRUSTED_HOST].connect(
- on_imap_trust_untrusted_host);
+ endpoint.untrusted_host.connect(on_imap_untrusted_host);
+ endpoint.notify[Endpoint.PROP_TRUST_UNTRUSTED_HOST].connect(on_imap_trust_untrusted_host);
+
+ network_monitor.network_changed.connect(on_network_changed);
+ network_monitor.notify["network-available"].connect(on_network_available_changed);
+
+ // get this started now
+ check_endpoint_reachable(null);
}
~ClientSessionManager() {
@@ -71,9 +93,11 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
warning("Destroying opened ClientSessionManager");
account_information.notify["imap-credentials"].disconnect(on_imap_credentials_notified);
- account_information.get_imap_endpoint().untrusted_host.disconnect(on_imap_untrusted_host);
- account_information.get_imap_endpoint().notify[Endpoint.PROP_TRUST_UNTRUSTED_HOST].disconnect(
- on_imap_trust_untrusted_host);
+ endpoint.untrusted_host.disconnect(on_imap_untrusted_host);
+ endpoint.notify[Endpoint.PROP_TRUST_UNTRUSTED_HOST].disconnect(on_imap_trust_untrusted_host);
+
+ network_monitor.network_changed.disconnect(on_network_changed);
+ network_monitor.notify["network-available"].disconnect(on_network_available_changed);
}
public async void open_async(Cancellable? cancellable) throws Error {
@@ -147,8 +171,13 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
return;
}
- while ((sessions.size + pending_sessions) < min_pool_size && !authentication_failed && is_open &&
!untrusted_host)
+ while ((sessions.size + pending_sessions) < min_pool_size
+ && !authentication_failed
+ && is_open
+ && !untrusted_host
+ && is_endpoint_reachable) {
schedule_new_authorized_session();
+ }
try {
sessions_mutex.release(ref token);
@@ -169,8 +198,7 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
try {
create_new_authorized_session.end(result);
} catch (Error err) {
- debug("Unable to create authorized session to %s: %s",
- account_information.get_imap_endpoint().to_string(), err.message);
+ debug("Unable to create authorized session to %s: %s", endpoint.to_string(), err.message);
// try again after a slight delay and bump up delay
if (authorized_session_error_retry_timeout_id != 0)
@@ -199,9 +227,12 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
throw new ImapError.UNAUTHENTICATED("Invalid ClientSessionManager credentials");
if (untrusted_host)
- throw new ImapError.UNAUTHENTICATED("Untrusted host %s",
account_information.get_imap_endpoint().to_string());
+ throw new ImapError.UNAUTHENTICATED("Untrusted host %s", endpoint.to_string());
+
+ if (!is_endpoint_reachable)
+ throw new ImapError.UNAVAILABLE("Host at %s is unreachable", endpoint.to_string());
- ClientSession new_session = new ClientSession(account_information.get_imap_endpoint());
+ ClientSession new_session = new ClientSession(endpoint);
// add session to pool before launching all the connect activity so error cases can properly
// back it out
@@ -456,7 +487,7 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
private void on_imap_trust_untrusted_host() {
// fired when the trust_untrusted_host property changes, indicating if the user has agreed
// to ignore the trust problems and continue connecting
- if (untrusted_host && account_information.get_imap_endpoint().trust_untrusted_host == Trillian.TRUE)
{
+ if (untrusted_host && endpoint.trust_untrusted_host == Trillian.TRUE) {
untrusted_host = false;
if (is_open)
@@ -464,11 +495,59 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
}
}
+ private void on_network_changed() {
+ // Always check if reachable because IMAP server could be on localhost. (This is a Linux
+ // program, after all...)
+ check_endpoint_reachable(null);
+ }
+
+ private void on_network_available_changed() {
+ // If network is available and endpoint is reachable, do nothing more, all is good,
+ // otherwise check (see note in on_network_changed)
+ if (network_monitor.network_available && is_endpoint_reachable)
+ return;
+
+ check_endpoint_reachable(null);
+ }
+
+ private void check_endpoint_reachable(Cancellable? cancellable) {
+ if (checking_reachable)
+ return;
+
+ debug("Checking if IMAP host %s reachable...", endpoint.to_string());
+
+ checking_reachable = true;
+ check_endpoint_reachable_async.begin(cancellable);
+ }
+
+ // Use check_endpoint_reachable to properly schedule
+ private async void check_endpoint_reachable_async(Cancellable? cancellable) {
+ try {
+ is_endpoint_reachable = yield network_monitor.can_reach_async(endpoint.remote_address,
+ cancellable);
+ message("IMAP host %s considered %s", endpoint.to_string(),
+ is_endpoint_reachable ? "reachable" : "unreachable");
+ } catch (Error err) {
+ // If cancelled, don't change anything
+ if (err is IOError.CANCELLED)
+ return;
+
+ message("Error determining if IMAP host %s is reachable, treating as unreachable: %s",
+ endpoint.to_string(), err.message);
+ is_endpoint_reachable = false;
+ } finally {
+ checking_reachable = false;
+ }
+
+ if (is_endpoint_reachable)
+ adjust_session_pool.begin();
+ }
+
/**
* Use only for debugging and logging.
*/
public string to_string() {
- return account_information.get_imap_endpoint().to_string();
+ return endpoint.to_string();
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]