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