From f9436b63f1f7de08f8c2c97878c183495bb3c6f6 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Thu, 24 Aug 2017 23:24:04 +0200 Subject: [PATCH] connection: keep-alive pings, act upon connection change (VPN) --- libdino/CMakeLists.txt | 3 +- ...tworkmanager.vala => network_manager.vala} | 0 .../dbus/network_manager_dbus_properties.vala | 14 +++++ libdino/src/service/connection_manager.vala | 54 ++++++++++++++++--- 4 files changed, 63 insertions(+), 8 deletions(-) rename libdino/src/dbus/{networkmanager.vala => network_manager.vala} (100%) create mode 100644 libdino/src/dbus/network_manager_dbus_properties.vala diff --git a/libdino/CMakeLists.txt b/libdino/CMakeLists.txt index c19a7b1b..68ac8e5b 100644 --- a/libdino/CMakeLists.txt +++ b/libdino/CMakeLists.txt @@ -11,7 +11,8 @@ SOURCES src/application.vala src/dbus/login1.vala - src/dbus/networkmanager.vala + src/dbus/network_manager.vala + src/dbus/network_manager_dbus_properties.vala src/dbus/upower.vala src/entity/account.vala diff --git a/libdino/src/dbus/networkmanager.vala b/libdino/src/dbus/network_manager.vala similarity index 100% rename from libdino/src/dbus/networkmanager.vala rename to libdino/src/dbus/network_manager.vala diff --git a/libdino/src/dbus/network_manager_dbus_properties.vala b/libdino/src/dbus/network_manager_dbus_properties.vala new file mode 100644 index 00000000..37cf76cb --- /dev/null +++ b/libdino/src/dbus/network_manager_dbus_properties.vala @@ -0,0 +1,14 @@ +[DBus (name = "org.freedesktop.DBus.Properties")] +public interface NetworkManagerDBusProperties : GLib.Object { + public signal void properties_changed(string iface, HashTable changed, string[] invalidated); +} + +public static NetworkManagerDBusProperties? get_dbus_properties() { + NetworkManagerDBusProperties? dbus_properties = null; + try { + dbus_properties = Bus.get_proxy_sync(BusType.SYSTEM, "org.freedesktop.DBus.Properties", "/org/freedesktop/NetworkManager"); + } catch (IOError e) { + stderr.printf("%s\n", e.message); + } + return dbus_properties; +} diff --git a/libdino/src/service/connection_manager.vala b/libdino/src/service/connection_manager.vala index d932d1cc..f7333bbd 100644 --- a/libdino/src/service/connection_manager.vala +++ b/libdino/src/service/connection_manager.vala @@ -20,9 +20,11 @@ public class ConnectionManager { private ArrayList connection_todo = new ArrayList(Account.equals_func); private HashMap connections = new HashMap(Account.hash_func, Account.equals_func); private HashMap connection_errors = new HashMap(Account.hash_func, Account.equals_func); + private HashMap connection_mutexes = new HashMap(Account.hash_func, Account.equals_func); private NetworkManager? network_manager; private Login1Manager? login1; + private NetworkManagerDBusProperties? dbus_properties; private ModuleManager module_manager; public string? log_options; @@ -48,12 +50,20 @@ public class ConnectionManager { public Core.XmppStream stream { get; set; } public ConnectionState connection_state { get; set; default = ConnectionState.DISCONNECTED; } public DateTime established { get; set; } + public DateTime last_activity { get; set; } public class Connection(Core.XmppStream stream, DateTime established) { this.stream = stream; this.established = established; } } + private class RecMutexWrap { + public RecMutex mutex = new RecMutex(); + public void lock() { mutex.lock(); } + public void unlock() { mutex.unlock(); } + public bool trylock() { return mutex.trylock(); } + } + public ConnectionManager(ModuleManager module_manager) { this.module_manager = module_manager; network_manager = get_network_manager(); @@ -64,6 +74,25 @@ public class ConnectionManager { if (login1 != null) { login1.PrepareForSleep.connect(on_prepare_for_sleep); } + dbus_properties = get_dbus_properties(); + if (dbus_properties != null) { + dbus_properties.properties_changed.connect((s, sv, sa) => { + foreach (string key in sv.get_keys()) { + if (key == "PrimaryConnection") { + print("primary connection changed\n"); + check_reconnects(); + } + } + }); + } + Timeout.add_seconds(60, () => { + foreach (Account account in connection_todo) { + if (connections[account].last_activity.compare(new DateTime.now_utc().add_minutes(-1)) < 0) { + check_reconnect(account); + } + } + return true; + }); } public Core.XmppStream? get_stream(Account account) { @@ -92,6 +121,7 @@ public class ConnectionManager { } public Core.XmppStream? connect(Account account) { + if (!connection_mutexes.contains(account)) connection_mutexes[account] = new RecMutexWrap(); if (!connection_todo.contains(account)) connection_todo.add(account); if (!connections.has_key(account)) { return connect_(account); @@ -113,6 +143,8 @@ public class ConnectionManager { } private Core.XmppStream? connect_(Account account, string? resource = null) { + if (!connection_mutexes[account].trylock()) return null; + if (connections.has_key(account)) connections[account].stream.remove_modules(); connection_errors.unset(account); if (resource == null) resource = account.resourcepart; @@ -133,6 +165,9 @@ public class ConnectionManager { set_connection_error(account, ConnectionError.Source.SASL, null); change_connection_state(account, ConnectionState.DISCONNECTED); }); + stream.received_node.connect(() => { + connections[account].last_activity = new DateTime.now_utc(); + }); new Thread (null, () => { try { stream.connect(account.domainpart); @@ -141,18 +176,20 @@ public class ConnectionManager { change_connection_state(account, ConnectionState.DISCONNECTED); if (!connection_todo.contains(account)) { connections.unset(account); - } else { - StreamError.Flag? flag = stream.get_flag(StreamError.Flag.IDENTITY); - if (flag != null) { - set_connection_error(account, ConnectionError.Source.STREAM_ERROR, flag.error_type); - } - interpret_connection_error(account); + return null; } + StreamError.Flag? flag = stream.get_flag(StreamError.Flag.IDENTITY); + if (flag != null) { + set_connection_error(account, ConnectionError.Source.STREAM_ERROR, flag.error_type); + } + interpret_connection_error(account); } + connection_mutexes[account].unlock(); return null; }); stream_opened(account, stream); + connection_mutexes[account].unlock(); return stream; } @@ -182,7 +219,7 @@ public class ConnectionManager { } print(@"recovering in $wait_sec\n"); Timeout.add_seconds(wait_sec, () => { - connect_(account); + check_reconnect(account); return false; }); } @@ -194,6 +231,7 @@ public class ConnectionManager { } private void check_reconnect(Account account) { + if (!connection_mutexes[account].trylock()) return; bool acked = false; Core.XmppStream stream = connections[account].stream; @@ -210,6 +248,8 @@ public class ConnectionManager { try { connections[account].stream.disconnect(); } catch (Error e) { } + connect_(account); + connection_mutexes[account].unlock(); return false; }); }