aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Schneppe <christian@pix-art.de>2019-06-25 21:17:32 +0200
committerChristian Schneppe <christian@pix-art.de>2019-06-25 21:47:19 +0200
commit1d8fa7e99dc1304ece611bff99d12f52981ab1f9 (patch)
tree91e3790c1ad84b5413238c74b2c09b080234a893
parent73c8feea13a526259ee5bb58e639e31ad781fd79 (diff)
Revert "Networkstack - let OS decide IPv4 or IPv6 (#267)"
This reverts commit e6a15597904019f68c02e6fd8f61fb6de0b13324. If there is IPv6 available but the server doesn't listen to it, the connection will not be established
-rw-r--r--src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java56
-rw-r--r--src/main/java/de/pixart/messenger/utils/AndroidUsingExecLowPriority.java92
-rw-r--r--src/main/java/de/pixart/messenger/utils/AndroidUsingLinkProperties.java91
-rw-r--r--src/main/java/de/pixart/messenger/utils/Resolver.java115
-rw-r--r--src/main/java/de/pixart/messenger/xmpp/XmppConnection.java23
5 files changed, 361 insertions, 16 deletions
diff --git a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
index 243db470a..ba0f7927d 100644
--- a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
+++ b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
@@ -55,6 +55,7 @@ import de.pixart.messenger.entities.ServiceDiscoveryResult;
import de.pixart.messenger.services.ShortcutService;
import de.pixart.messenger.utils.CryptoHelper;
import de.pixart.messenger.utils.FtsUtils;
+import de.pixart.messenger.utils.Resolver;
import de.pixart.messenger.xmpp.InvalidJid;
import de.pixart.messenger.xmpp.mam.MamReference;
import rocks.xmpp.addr.Jid;
@@ -62,7 +63,7 @@ import rocks.xmpp.addr.Jid;
public class DatabaseBackend extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "history";
- public static final int DATABASE_VERSION = 47; // = Conversations DATABASE_VERSION + 3
+ public static final int DATABASE_VERSION = 48; // = Conversations DATABASE_VERSION + 4
private static DatabaseBackend instance = null;
private static String CREATE_CONTATCS_STATEMENT = "create table "
@@ -150,6 +151,17 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ ") ON CONFLICT IGNORE"
+ ");";
+ private static String RESOLVER_RESULTS_TABLENAME = "resolver_results";
+ private static String CREATE_RESOLVER_RESULTS_TABLE = "create table " + RESOLVER_RESULTS_TABLENAME + "("
+ + Resolver.Result.DOMAIN + " TEXT,"
+ + Resolver.Result.HOSTNAME + " TEXT,"
+ + Resolver.Result.IP + " BLOB,"
+ + Resolver.Result.PRIORITY + " NUMBER,"
+ + Resolver.Result.DIRECT_TLS + " NUMBER,"
+ + Resolver.Result.AUTHENTICATED + " NUMBER,"
+ + Resolver.Result.PORT + " NUMBER,"
+ + "UNIQUE(" + Resolver.Result.DOMAIN + ") ON CONFLICT REPLACE"
+ + ");";
private static String CREATE_MESSAGE_TIME_INDEX = "create INDEX message_time_index ON " + Message.TABLENAME + "(" + Message.TIME_SENT + ")";
private static String CREATE_MESSAGE_CONVERSATION_INDEX = "create INDEX message_conversation_index ON " + Message.TABLENAME + "(" + Message.CONVERSATION + ")";
private static String CREATE_MESSAGE_DELETED_INDEX = "create index message_deleted_index ON " + Message.TABLENAME + "(" + Message.DELETED + ")";
@@ -247,6 +259,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.execSQL(CREATE_SIGNED_PREKEYS_STATEMENT);
db.execSQL(CREATE_IDENTITIES_STATEMENT);
db.execSQL(CREATE_PRESENCE_TEMPLATES_STATEMENT);
+ db.execSQL(CREATE_RESOLVER_RESULTS_TABLE);
db.execSQL(CREATE_MESSAGE_INDEX_TABLE);
db.execSQL(CREATE_MESSAGE_INSERT_TRIGGER);
db.execSQL(CREATE_MESSAGE_UPDATE_TRIGGER);
@@ -516,6 +529,10 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.MARKABLE + " NUMBER DEFAULT 0");
}
+ if (oldVersion < 40 && newVersion >= 40) {
+ db.execSQL(CREATE_RESOLVER_RESULTS_TABLE);
+ }
+
if (oldVersion < 42 && newVersion >= 42) {
db.execSQL(CREATE_MESSAGE_INDEX_TABLE);
db.execSQL(CREATE_MESSAGE_INSERT_TRIGGER);
@@ -544,7 +561,14 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + SQLiteAxolotlStore.IDENTITIES_TABLENAME + " ADD COLUMN " + SQLiteAxolotlStore.TRUSTED); // TODO - just to make old databases importable, column isn't needed at all
}
}
- db.execSQL("DROP TABLE resolver_results");
+
+ if (oldVersion < 48 && newVersion >= 48) {
+ try {
+ db.execSQL(CREATE_RESOLVER_RESULTS_TABLE);
+ } catch (Exception e) {
+ //ignore
+ }
+ }
}
private boolean isColumnExisting(SQLiteDatabase db, String TableName, String ColumnName) {
@@ -681,6 +705,34 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return result;
}
+ public void saveResolverResult(String domain, Resolver.Result result) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ ContentValues contentValues = result.toContentValues();
+ contentValues.put(Resolver.Result.DOMAIN, domain);
+ db.insert(RESOLVER_RESULTS_TABLENAME, null, contentValues);
+ }
+
+ public synchronized Resolver.Result findResolverResult(String domain) {
+ SQLiteDatabase db = this.getReadableDatabase();
+ String where = Resolver.Result.DOMAIN + "=?";
+ String[] whereArgs = {domain};
+ final Cursor cursor = db.query(RESOLVER_RESULTS_TABLENAME, null, where, whereArgs, null, null, null);
+ Resolver.Result result = null;
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ result = Resolver.Result.fromCursor(cursor);
+ }
+ } catch (Exception e) {
+ Log.d(Config.LOGTAG, "unable to find cached resolver result in database " + e.getMessage());
+ return null;
+ } finally {
+ cursor.close();
+ }
+ }
+ return result;
+ }
+
public void insertPresenceTemplate(PresenceTemplate template) {
SQLiteDatabase db = this.getWritableDatabase();
String whereToDelete = PresenceTemplate.MESSAGE + "=?";
diff --git a/src/main/java/de/pixart/messenger/utils/AndroidUsingExecLowPriority.java b/src/main/java/de/pixart/messenger/utils/AndroidUsingExecLowPriority.java
new file mode 100644
index 000000000..6097fcd03
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/utils/AndroidUsingExecLowPriority.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2015-2016 the original author or authors
+ *
+ * This software is licensed under the Apache License, Version 2.0,
+ * the GNU Lesser General Public License version 2 or later ("LGPL")
+ * and the WTFPL.
+ * You may choose either license to govern your use of this software only
+ * upon the condition that you accept all of the terms of either
+ * the Apache License 2.0, the LGPL 2.1+ or the WTFPL.
+ */
+
+package de.pixart.messenger.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.net.InetAddress;
+import java.util.HashSet;
+import java.util.logging.Level;
+
+import de.measite.minidns.dnsserverlookup.AbstractDNSServerLookupMechanism;
+import de.measite.minidns.dnsserverlookup.AndroidUsingReflection;
+import de.measite.minidns.dnsserverlookup.DNSServerLookupMechanism;
+import de.measite.minidns.util.PlatformDetection;
+
+/**
+ * Try to retrieve the list of DNS server by executing getprop.
+ */
+public class AndroidUsingExecLowPriority extends AbstractDNSServerLookupMechanism {
+
+ public static final DNSServerLookupMechanism INSTANCE = new AndroidUsingExecLowPriority();
+ public static final int PRIORITY = AndroidUsingReflection.PRIORITY + 1;
+
+ private AndroidUsingExecLowPriority() {
+ super(AndroidUsingExecLowPriority.class.getSimpleName(), PRIORITY);
+ }
+
+ @Override
+ public String[] getDnsServerAddresses() {
+ try {
+ Process process = Runtime.getRuntime().exec("getprop");
+ InputStream inputStream = process.getInputStream();
+ LineNumberReader lnr = new LineNumberReader(
+ new InputStreamReader(inputStream));
+ String line;
+ HashSet<String> server = new HashSet<>(6);
+ while ((line = lnr.readLine()) != null) {
+ int split = line.indexOf("]: [");
+ if (split == -1) {
+ continue;
+ }
+ String property = line.substring(1, split);
+ String value = line.substring(split + 4, line.length() - 1);
+
+ if (value.isEmpty()) {
+ continue;
+ }
+
+ if (property.endsWith(".dns") || property.endsWith(".dns1") ||
+ property.endsWith(".dns2") || property.endsWith(".dns3") ||
+ property.endsWith(".dns4")) {
+
+ // normalize the address
+
+ InetAddress ip = InetAddress.getByName(value);
+
+ if (ip == null) continue;
+
+ value = ip.getHostAddress();
+
+ if (value == null) continue;
+ if (value.length() == 0) continue;
+
+ server.add(value);
+ }
+ }
+ if (server.size() > 0) {
+ return server.toArray(new String[server.size()]);
+ }
+ } catch (IOException e) {
+ LOGGER.log(Level.WARNING, "Exception in findDNSByExec", e);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return PlatformDetection.isAndroid();
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/utils/AndroidUsingLinkProperties.java b/src/main/java/de/pixart/messenger/utils/AndroidUsingLinkProperties.java
new file mode 100644
index 000000000..1c0fca8bb
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/utils/AndroidUsingLinkProperties.java
@@ -0,0 +1,91 @@
+package de.pixart.messenger.utils;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkInfo;
+import android.net.RouteInfo;
+import android.os.Build;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.measite.minidns.dnsserverlookup.AbstractDNSServerLookupMechanism;
+import de.measite.minidns.dnsserverlookup.AndroidUsingExec;
+
+public class AndroidUsingLinkProperties extends AbstractDNSServerLookupMechanism {
+
+ private final Context context;
+
+ protected AndroidUsingLinkProperties(Context context) {
+ super(AndroidUsingLinkProperties.class.getSimpleName(), AndroidUsingExec.PRIORITY - 1);
+ this.context = context;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
+ }
+
+ @Override
+ @TargetApi(21)
+ public String[] getDnsServerAddresses() {
+ ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ Network[] networks = connectivityManager == null ? null : connectivityManager.getAllNetworks();
+ if (networks == null) {
+ return new String[0];
+ }
+ final Network activeNetwork = getActiveNetwork(connectivityManager);
+ List<String> servers = new ArrayList<>();
+ int vpnOffset = 0;
+ for (Network network : networks) {
+ LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
+ if (linkProperties == null) {
+ continue;
+ }
+ NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
+ final boolean isActiveNetwork = network.equals(activeNetwork);
+ if (isActiveNetwork) {
+ if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_VPN) {
+ final List<String> tmp = getIPv4First(linkProperties.getDnsServers());
+ servers.addAll(0, tmp);
+ vpnOffset += tmp.size();
+ } else {
+ servers.addAll(vpnOffset, getIPv4First(linkProperties.getDnsServers()));
+ }
+ }
+ }
+ return servers.toArray(new String[servers.size()]);
+ }
+
+ @TargetApi(23)
+ private static Network getActiveNetwork(ConnectivityManager cm) {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? cm.getActiveNetwork() : null;
+ }
+
+ private static List<String> getIPv4First(List<InetAddress> in) {
+ List<String> out = new ArrayList<>();
+ for (InetAddress addr : in) {
+ if (addr instanceof Inet4Address) {
+ out.add(0, addr.getHostAddress());
+ } else {
+ out.add(addr.getHostAddress());
+ }
+ }
+ return out;
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private static boolean hasDefaultRoute(LinkProperties linkProperties) {
+ for (RouteInfo route : linkProperties.getRoutes()) {
+ if (route.isDefaultRoute()) {
+ return true;
+ }
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/utils/Resolver.java b/src/main/java/de/pixart/messenger/utils/Resolver.java
index edde83088..2378c429e 100644
--- a/src/main/java/de/pixart/messenger/utils/Resolver.java
+++ b/src/main/java/de/pixart/messenger/utils/Resolver.java
@@ -7,6 +7,9 @@ import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Field;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -17,12 +20,16 @@ import de.measite.minidns.DNSName;
import de.measite.minidns.Question;
import de.measite.minidns.Record;
import de.measite.minidns.dnssec.DNSSECResultNotAuthenticException;
+import de.measite.minidns.dnsserverlookup.AndroidUsingExec;
import de.measite.minidns.hla.DnssecResolverApi;
import de.measite.minidns.hla.ResolverApi;
import de.measite.minidns.hla.ResolverResult;
import de.measite.minidns.iterative.ReliableDNSClient;
+import de.measite.minidns.record.A;
+import de.measite.minidns.record.AAAA;
import de.measite.minidns.record.CNAME;
import de.measite.minidns.record.Data;
+import de.measite.minidns.record.InternetAddressRR;
import de.measite.minidns.record.SRV;
import de.pixart.messenger.Config;
import de.pixart.messenger.R;
@@ -32,13 +39,16 @@ public class Resolver {
public static final int DEFAULT_PORT_XMPP = 5222;
private static final String DIRECT_TLS_SERVICE = "_xmpps-client";
- private static final String STARTTLS_SERVICE = "_xmpp-client";
+ private static final String STARTTLS_SERICE = "_xmpp-client";
private static XmppConnectionService SERVICE = null;
public static void init(XmppConnectionService service) {
Resolver.SERVICE = service;
+ DNSClient.removeDNSServerLookupMechanism(AndroidUsingExec.INSTANCE);
+ DNSClient.addDnsServerLookupMechanism(AndroidUsingExecLowPriority.INSTANCE);
+ DNSClient.addDnsServerLookupMechanism(new AndroidUsingLinkProperties(service));
final AbstractDNSClient client = ResolverApi.INSTANCE.getClient();
if (client instanceof ReliableDNSClient) {
disableHardcodedDnsServers((ReliableDNSClient) client);
@@ -138,41 +148,91 @@ public class Resolver {
if (!IP.matches(domain)) {
return Collections.emptyList();
}
- return Collections.singletonList(Result.createDefault(DNSName.from(domain)));
+ try {
+ Result result = new Result();
+ result.ip = InetAddress.getByName(domain);
+ result.port = DEFAULT_PORT_XMPP;
+ return Collections.singletonList(result);
+ } catch (UnknownHostException e) {
+ return Collections.emptyList();
+ }
}
private static List<Result> resolveSrv(String domain, final boolean directTls) throws IOException {
- DNSName dnsName = DNSName.from((directTls ? DIRECT_TLS_SERVICE : STARTTLS_SERVICE) + "._tcp." + domain);
+ DNSName dnsName = DNSName.from((directTls ? DIRECT_TLS_SERVICE : STARTTLS_SERICE) + "._tcp." + domain);
ResolverResult<SRV> result = resolveWithFallback(dnsName, SRV.class);
final List<Result> results = new ArrayList<>();
+ final List<Thread> threads = new ArrayList<>();
for (SRV record : result.getAnswersOrEmptySet()) {
if (record.name.length() == 0 && record.priority == 0) {
continue;
}
+ threads.add(new Thread(() -> {
+ final List<Result> ipv4s = resolveIp(record, A.class, result.isAuthenticData(), directTls);
+ if (ipv4s.size() == 0) {
Result resolverResult = Result.fromRecord(record, directTls);
- resolverResult.authenticated = result.isAuthenticData();
- results.add(resolverResult);
+ resolverResult.authenticated = resolverResult.isAuthenticated();
+ ipv4s.add(resolverResult);
+ }
+ synchronized (results) {
+ results.addAll(ipv4s);
}
+ }));
+ threads.add(new Thread(() -> {
+ final List<Result> ipv6s = resolveIp(record, AAAA.class, result.isAuthenticData(), directTls);
+ synchronized (results) {
+ results.addAll(ipv6s);
+ }
+ }));
+ }
+ for (Thread thread : threads) {
+ thread.start();
+ }
+ for (Thread thread : threads) {
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ return Collections.emptyList();
+ }
+ }
return results;
}
+ private static <D extends InternetAddressRR> List<Result> resolveIp(SRV srv, Class<D> type, boolean authenticated, boolean directTls) {
+ List<Result> list = new ArrayList<>();
+ try {
+ ResolverResult<D> results = resolveWithFallback(srv.name, type, authenticated);
+ for (D record : results.getAnswersOrEmptySet()) {
+ Result resolverResult = Result.fromRecord(srv, directTls);
+ resolverResult.authenticated = results.isAuthenticData() && authenticated;
+ resolverResult.ip = record.getInetAddress();
+ list.add(resolverResult);
+ }
+ } catch (Throwable t) {
+ Log.d(Config.LOGTAG, Resolver.class.getSimpleName() + ": error resolving " + type.getSimpleName() + " " + t.getMessage());
+ }
+ return list;
+ }
+
private static List<Result> resolveNoSrvRecords(DNSName dnsName, boolean withCnames) {
List<Result> results = new ArrayList<>();
- Boolean resolveCNAME = false;
try {
- if (withCnames) {
+ for (A a : resolveWithFallback(dnsName, A.class, false).getAnswersOrEmptySet()) {
+ results.add(Result.createDefault(dnsName, a.getInetAddress()));
+ }
+ for (AAAA aaaa : resolveWithFallback(dnsName, AAAA.class, false).getAnswersOrEmptySet()) {
+ results.add(Result.createDefault(dnsName, aaaa.getInetAddress()));
+ }
+ if (results.size() == 0 && withCnames) {
for (CNAME cname : resolveWithFallback(dnsName, CNAME.class, false).getAnswersOrEmptySet()) {
results.addAll(resolveNoSrvRecords(cname.name, false));
- resolveCNAME = true;
}
}
} catch (Throwable throwable) {
Log.d(Config.LOGTAG, Resolver.class.getSimpleName() + "error resolving fallback records", throwable);
}
- if(!resolveCNAME) {
results.add(Result.createDefault(dnsName));
- }
return results;
}
@@ -203,11 +263,13 @@ public class Resolver {
public static class Result implements Comparable<Result> {
public static final String DOMAIN = "domain";
+ public static final String IP = "ip";
public static final String HOSTNAME = "hostname";
public static final String PORT = "port";
public static final String PRIORITY = "priority";
public static final String DIRECT_TLS = "directTls";
public static final String AUTHENTICATED = "authenticated";
+ private InetAddress ip;
private DNSName hostname;
private int port = DEFAULT_PORT_XMPP;
private boolean directTls = false;
@@ -223,15 +285,25 @@ public class Resolver {
return result;
}
- static Result createDefault(DNSName hostname) {
+ static Result createDefault(DNSName hostname, InetAddress ip) {
Result result = new Result();
result.port = DEFAULT_PORT_XMPP;
result.hostname = hostname;
+ result.ip = ip;
return result;
}
+ static Result createDefault(DNSName hostname) {
+ return createDefault(hostname, null);
+ }
+
public static Result fromCursor(Cursor cursor) {
final Result result = new Result();
+ try {
+ result.ip = InetAddress.getByAddress(cursor.getBlob(cursor.getColumnIndex(IP)));
+ } catch (UnknownHostException e) {
+ result.ip = null;
+ }
final String hostname = cursor.getString(cursor.getColumnIndex(HOSTNAME));
result.hostname = hostname == null ? null : DNSName.from(hostname);
result.port = cursor.getInt(cursor.getColumnIndex(PORT));
@@ -252,12 +324,14 @@ public class Resolver {
if (directTls != result.directTls) return false;
if (authenticated != result.authenticated) return false;
if (priority != result.priority) return false;
+ if (ip != null ? !ip.equals(result.ip) : result.ip != null) return false;
return hostname != null ? hostname.equals(result.hostname) : result.hostname == null;
}
@Override
public int hashCode() {
- int result = hostname != null ? hostname.hashCode() : 0;
+ int result = ip != null ? ip.hashCode() : 0;
+ result = 31 * result + (hostname != null ? hostname.hashCode() : 0);
result = 31 * result + port;
result = 31 * result + (directTls ? 1 : 0);
result = 31 * result + (authenticated ? 1 : 0);
@@ -265,6 +339,10 @@ public class Resolver {
return result;
}
+ public InetAddress getIp() {
+ return ip;
+ }
+
public int getPort() {
return port;
}
@@ -284,6 +362,7 @@ public class Resolver {
@Override
public String toString() {
return "Result{" +
+ "ip='" + (ip == null ? null : ip.getHostAddress()) + '\'' +
", hostame='" + hostname.toString() + '\'' +
", port=" + port +
", directTls=" + directTls +
@@ -296,8 +375,18 @@ public class Resolver {
public int compareTo(@NonNull Result result) {
if (result.priority == priority) {
if (directTls == result.directTls) {
+ if (ip == null && result.ip == null) {
+ return 0;
+ } else if (ip != null && result.ip != null) {
+ if (ip instanceof Inet4Address && result.ip instanceof Inet4Address) {
return 0;
} else {
+ return ip instanceof Inet4Address ? -1 : 1;
+ }
+ } else {
+ return ip != null ? -1 : 1;
+ }
+ } else {
return directTls ? -1 : 1;
}
} else {
@@ -307,6 +396,7 @@ public class Resolver {
public ContentValues toContentValues() {
final ContentValues contentValues = new ContentValues();
+ contentValues.put(IP, ip == null ? null : ip.getAddress());
contentValues.put(HOSTNAME, hostname == null ? null : hostname.toString());
contentValues.put(PORT, port);
contentValues.put(PRIORITY, priority);
@@ -315,5 +405,4 @@ public class Resolver {
return contentValues;
}
}
-
} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
index 9a72203b7..3a7e41c9a 100644
--- a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
+++ b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
@@ -320,6 +320,16 @@ public class XmppConnection implements Runnable {
Log.e(Config.LOGTAG, account.getJid().asBareJid() + ": Resolver results were empty");
return;
}
+ final Resolver.Result storedBackupResult;
+ if (hardcoded) {
+ storedBackupResult = null;
+ } else {
+ storedBackupResult = mXmppConnectionService.databaseBackend.findResolverResult(domain);
+ if (storedBackupResult != null && !results.contains(storedBackupResult)) {
+ results.add(storedBackupResult);
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": loaded backup resolver result from db: " + storedBackupResult);
+ }
+ }
for (Iterator<Resolver.Result> iterator = results.iterator(); iterator.hasNext(); ) {
final Resolver.Result result = iterator.next();
if (Thread.currentThread().isInterrupted()) {
@@ -331,10 +341,18 @@ public class XmppConnection implements Runnable {
features.encryptionEnabled = result.isDirectTls();
verifiedHostname = result.isAuthenticated() ? result.getHostname().toString() : null;
Log.d(Config.LOGTAG, "verified hostname " + verifiedHostname);
- final InetSocketAddress addr = new InetSocketAddress(IDN.toASCII(result.getHostname().toString()), result.getPort());
+ final InetSocketAddress addr;
+ if (result.getIp() != null) {
+ addr = new InetSocketAddress(result.getIp(), result.getPort());
+ Log.d(Config.LOGTAG, account.getJid().asBareJid().toString()
+ + ": using values from resolver " + (result.getHostname() == null ? "" : result.getHostname().toString()
+ + "/") + result.getIp().getHostAddress() + ":" + result.getPort() + " tls: " + features.encryptionEnabled);
+ } else {
+ addr = new InetSocketAddress(IDN.toASCII(result.getHostname().toString()), result.getPort());
Log.d(Config.LOGTAG, account.getJid().asBareJid().toString()
+ ": using values from resolver "
+ result.getHostname().toString() + ":" + result.getPort() + " tls: " + features.encryptionEnabled);
+ }
if (!features.encryptionEnabled) {
localSocket = new Socket();
@@ -362,6 +380,9 @@ public class XmppConnection implements Runnable {
localSocket.setSoTimeout(Config.SOCKET_TIMEOUT * 1000);
if (startXmpp(localSocket)) {
localSocket.setSoTimeout(0); //reset to 0; once the connection is established we don’t want this
+ if (!hardcoded && !result.equals(storedBackupResult)) {
+ mXmppConnectionService.databaseBackend.saveResolverResult(domain, result);
+ }
break; // successfully connected to server that speaks xmpp
} else {
FileBackend.close(localSocket);