From af01f4173d76de33dcc3f547f04fdff49892d195 Mon Sep 17 00:00:00 2001 From: M66B Date: Sun, 8 Nov 2020 20:51:44 +0100 Subject: [PATCH] Added option to enable TCP keep alive --- .../java/eu/faircode/email/ApplicationEx.java | 8 +++++++ .../java/eu/faircode/email/EmailService.java | 22 +++++++++++++++---- .../email/FragmentOptionsConnection.java | 17 +++++++++++++- .../eu/faircode/email/ServiceSynchronize.java | 2 +- .../layout/fragment_options_connection.xml | 14 +++++++++++- app/src/main/res/values/strings.xml | 1 + 6 files changed, 57 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/ApplicationEx.java b/app/src/main/java/eu/faircode/email/ApplicationEx.java index 6ddc11bd17..e53a98f291 100644 --- a/app/src/main/java/eu/faircode/email/ApplicationEx.java +++ b/app/src/main/java/eu/faircode/email/ApplicationEx.java @@ -88,6 +88,14 @@ public class ApplicationEx extends Application implements SharedPreferences.OnSh SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); final boolean crash_reports = prefs.getBoolean("crash_reports", false); + + try { + boolean tcp_keep_alive = prefs.getBoolean("tcp_keep_alive", true); + System.setProperty("fairemail.tcp_keep_alive", Boolean.toString(tcp_keep_alive)); + } catch (Throwable ex) { + Log.e(ex); + } + prefs.registerOnSharedPreferenceChangeListener(this); prev = Thread.getDefaultUncaughtExceptionHandler(); diff --git a/app/src/main/java/eu/faircode/email/EmailService.java b/app/src/main/java/eu/faircode/email/EmailService.java index d89fe8123c..1759511c1f 100644 --- a/app/src/main/java/eu/faircode/email/EmailService.java +++ b/app/src/main/java/eu/faircode/email/EmailService.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.ParcelFileDescriptor; import android.security.KeyChain; +import android.system.ErrnoException; import android.text.TextUtils; import androidx.annotation.NonNull; @@ -131,6 +132,8 @@ public class EmailService implements AutoCloseable { private final static int FETCH_SIZE = 1024 * 1024; // bytes, default 16K private final static int POOL_TIMEOUT = 45 * 1000; // milliseconds, default 45 sec + private final static int TCP_KEEP_ALIVE_INTERVAL = 9 * 60; // seconds + private static final int APPEND_BUFFER_SIZE = 4 * 1024 * 1024; // bytes // https://developer.android.com/reference/javax/net/ssl/SSLSocket.html#protocols @@ -1047,10 +1050,21 @@ public class EmailService implements AutoCloseable { socket.setSoLinger(false, -1); } - int fd = ParcelFileDescriptor.fromSocket(socket).getFd(); - int errno = jni_socket_keep_alive(fd, 9 * 60); - if (errno != 0) - Log.e("Socket TCP_KEEPIDLE=" + errno); + try { + boolean tcp_keep_alive = Boolean.parseBoolean(System.getProperty("fairemail.tcp_keep_alive")); + if (tcp_keep_alive) { + Log.i("Enabling TCP keep alive"); + + int fd = ParcelFileDescriptor.fromSocket(socket).getFd(); + int errno = jni_socket_keep_alive(fd, TCP_KEEP_ALIVE_INTERVAL); + if (errno != 0) + throw new ErrnoException("TCP_KEEPIDLE", errno); + + socket.setKeepAlive(true); + } + } catch (Throwable ex) { + Log.e(ex); + } } class UntrustedException extends MessagingException { diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java b/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java index 05d22bdc5a..cbaf75fd5d 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java @@ -61,6 +61,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre private SwitchCompat swRlah; private EditText etTimeout; private SwitchCompat swPreferIp4; + private SwitchCompat swTcpKeepAlive; private SwitchCompat swSslHarden; private Button btnManage; private TextView tvNetworkMetered; @@ -68,7 +69,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre private TextView tvNetworkInfo; private final static String[] RESET_OPTIONS = new String[]{ - "metered", "download", "roaming", "rlah", "timeout", "prefer_ip4", "ssl_harden" + "metered", "download", "roaming", "rlah", "timeout", "prefer_ip4", "tcp_keep_alive", "ssl_harden" }; @Override @@ -87,6 +88,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre swRlah = view.findViewById(R.id.swRlah); etTimeout = view.findViewById(R.id.etTimeout); swPreferIp4 = view.findViewById(R.id.swPreferIp4); + swTcpKeepAlive = view.findViewById(R.id.swTcpKeepAlive); swSslHarden = view.findViewById(R.id.swSslHarden); btnManage = view.findViewById(R.id.btnManage); @@ -166,6 +168,18 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre } }); + swTcpKeepAlive.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + try { + System.setProperty("fairemail.tcp_keep_alive", Boolean.toString(checked)); + } catch (Throwable ex) { + Log.e(ex); + } + prefs.edit().putBoolean("tcp_keep_alive", checked).apply(); + } + }); + swSslHarden.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { @@ -281,6 +295,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre etTimeout.setHint(Integer.toString(EmailService.DEFAULT_CONNECT_TIMEOUT)); swPreferIp4.setChecked(prefs.getBoolean("prefer_ip4", true)); + swTcpKeepAlive.setChecked(prefs.getBoolean("tcp_keep_alive", true)); swSslHarden.setChecked(prefs.getBoolean("ssl_harden", false)); } diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index 339bde8529..54a1829a89 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -134,7 +134,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences "sync_kept", "sync_folders", "sync_shared_folders", - "prefer_ip4", "ssl_harden", // force reconnect + "prefer_ip4", "tcp_keep_alive", "ssl_harden", // force reconnect "badge", "unseen_ignored", // force update badge/widget "protocol", "debug", // force reconnect "auth_plain", diff --git a/app/src/main/res/layout/fragment_options_connection.xml b/app/src/main/res/layout/fragment_options_connection.xml index abfa0ed287..c6f856c79e 100644 --- a/app/src/main/res/layout/fragment_options_connection.xml +++ b/app/src/main/res/layout/fragment_options_connection.xml @@ -196,6 +196,18 @@ app:layout_constraintTop_toBottomOf="@id/etTimeout" app:switchPadding="12dp" /> + + Roam like at home Connection timeout (seconds) Prefer IPv4 over IPv6 + TCP keep alive Harden SSL connections Manage connectivity