~singpolyma/cheogram-android

2e380ed7923ddc3b0018f91b832aa0fd178c8c51 — Daniel Gultsch 6 years ago 5d9d725
upgrade minidns. refactored dns utils
M build.gradle => build.gradle +1 -1
@@ 33,7 33,7 @@ dependencies {
    compile 'org.gnu.inet:libidn:1.15'
    compile 'com.google.zxing:core:3.2.1'
    compile 'com.google.zxing:android-integration:3.2.1'
    compile 'de.measite.minidns:minidns:0.1.7'
    compile 'de.measite.minidns:minidns-hla:0.2.1'
    compile 'de.timroes.android:EnhancedListView:0.3.4'
    compile 'me.leolin:ShortcutBadger:1.1.12@aar'
    compile 'com.kyleduo.switchbutton:library:1.2.8'

M src/main/java/eu/siacs/conversations/services/XmppConnectionService.java => src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +2 -0
@@ 114,6 114,7 @@ import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener;
import eu.siacs.conversations.utils.PRNGFixes;
import eu.siacs.conversations.utils.PhoneHelper;
import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor;
import eu.siacs.conversations.utils.Resolver;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.utils.XmppUri;


@@ 983,6 984,7 @@ public class XmppConnectionService extends Service {
	public void onCreate() {
		ExceptionHelper.init(getApplicationContext());
		PRNGFixes.apply();
		Resolver.registerLookupMechanism(this);
		this.mRandom = new SecureRandom();
		updateMemorizingTrustmanager();
		final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

A src/main/java/eu/siacs/conversations/utils/AndroidUsingLinkProperties.java => src/main/java/eu/siacs/conversations/utils/AndroidUsingLinkProperties.java +76 -0
@@ 0,0 1,76 @@
package eu.siacs.conversations.utils;

import android.annotation.TargetApi;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
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];
        }
        List<String> servers = new ArrayList<>();
        for(Network network : networks) {
            LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
            if (linkProperties != null) {
                if (hasDefaultRoute(linkProperties)) {
                    servers.addAll(0, getIPv4First(linkProperties.getDnsServers()));
                } else {
                    servers.addAll(getIPv4First(linkProperties.getDnsServers()));
                }
            }
        }
        return servers.toArray(new String[servers.size()]);
    }

    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.toString());
            } else {
                out.add(addr.toString());
            }
        }
        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;
    }
}

D src/main/java/eu/siacs/conversations/utils/DNSHelper.java => src/main/java/eu/siacs/conversations/utils/DNSHelper.java +0 -299
@@ 1,299 0,0 @@
package eu.siacs.conversations.utils;

import android.annotation.TargetApi;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.RouteInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.TreeMap;
import java.util.Map;
import java.util.regex.Pattern;

import de.measite.minidns.Client;
import de.measite.minidns.DNSMessage;
import de.measite.minidns.Record;
import de.measite.minidns.Record.CLASS;
import de.measite.minidns.Record.TYPE;
import de.measite.minidns.record.A;
import de.measite.minidns.record.AAAA;
import de.measite.minidns.record.Data;
import de.measite.minidns.record.SRV;
import de.measite.minidns.util.NameUtil;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.xmpp.jid.Jid;

public class DNSHelper {

	public static final Pattern PATTERN_IPV4 = Pattern.compile("\\A(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
	public static final Pattern PATTERN_IPV6_HEX4DECCOMPRESSED = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::((?:[0-9A-Fa-f]{1,4}:)*)(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
	public static final Pattern PATTERN_IPV6_6HEX4DEC = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}:){6,6})(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
	public static final Pattern PATTERN_IPV6_HEXCOMPRESSED = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)\\z");
	public static final Pattern PATTERN_IPV6 = Pattern.compile("\\A(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\z");

	protected static Client client = new Client();

	protected static Context context;

	public static Bundle getSRVRecord(final Jid jid, Context context) throws IOException {
		DNSHelper.context = context;
        final String host = jid.getDomainpart();
		final List<InetAddress> servers = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? getDnsServers(context) : getDnsServersPreLollipop();
		Bundle b = new Bundle();
		boolean interrupted = false;
		for(InetAddress server : servers) {
			if (Thread.currentThread().isInterrupted()) {
				interrupted = true;
				break;
			}
			b = queryDNS(host, server);
			if (b.containsKey("values")) {
				return b;
			}
		}
		if (!b.containsKey("values")) {
			Log.d(Config.LOGTAG,(interrupted ? "Thread interrupted during DNS query" :"all dns queries failed") + ". provide fallback A record");
			ArrayList<Parcelable> values = new ArrayList<>();
			values.add(createNamePortBundle(host, 5222, false));
			b.putParcelableArrayList("values",values);
		}
		return b;
	}

	@TargetApi(21)
	private static List<InetAddress> getDnsServers(Context context) {
		List<InetAddress> servers = new ArrayList<>();
		ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
		Network[] networks = connectivityManager == null ? null : connectivityManager.getAllNetworks();
		if (networks == null) {
			return getDnsServersPreLollipop();
		}
		for(int i = 0; i < networks.length; ++i) {
			LinkProperties linkProperties = connectivityManager.getLinkProperties(networks[i]);
			if (linkProperties != null) {
				if (hasDefaultRoute(linkProperties)) {
					servers.addAll(0, getIPv4First(linkProperties.getDnsServers()));
				} else {
					servers.addAll(getIPv4First(linkProperties.getDnsServers()));
				}
			}
		}
		if (servers.size() > 0) {
			Log.d(Config.LOGTAG, "used lollipop variant to discover dns servers in " + networks.length + " networks");
		}
		return servers.size() > 0 ? servers : getDnsServersPreLollipop();
	}

	private static List<InetAddress> getIPv4First(List<InetAddress> in) {
		List<InetAddress> out = new ArrayList<>();
		for(InetAddress addr : in) {
			if (addr instanceof Inet4Address) {
				out.add(0, addr);
			} else {
				out.add(addr);
			}
		}
		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;
	}

	private static List<InetAddress> getDnsServersPreLollipop() {
		List<InetAddress> servers = new ArrayList<>();
		String[] dns = client.findDNS();
		for(int i = 0; i < dns.length; ++i) {
			try {
				servers.add(InetAddress.getByName(dns[i]));
			} catch (UnknownHostException e) {
				//ignore
			}
		}
		return servers;
	}

	private static class TlsSrv {
		private final SRV srv;
		private final boolean tls;

		public TlsSrv(SRV srv, boolean tls) {
			this.srv = srv;
			this.tls = tls;
		}
	}

	private static void fillSrvMaps(final String qname, final InetAddress dnsServer, final Map<Integer, List<TlsSrv>> priorities, final Map<String, List<String>> ips4, final Map<String, List<String>> ips6, final boolean tls) throws IOException {
		final DNSMessage message = client.query(qname, TYPE.SRV, CLASS.IN, dnsServer.getHostAddress());
		for (Record[] rrset : new Record[][] { message.getAnswers(), message.getAdditionalResourceRecords() }) {
			for (Record rr : rrset) {
				Data d = rr.getPayload();
				final String name = rr.getName() != null ? rr.getName().toLowerCase(Locale.US) : null;
				if (d instanceof SRV && NameUtil.idnEquals(qname, name)) {
					SRV srv = (SRV) d;
					if (!priorities.containsKey(srv.getPriority())) {
						priorities.put(srv.getPriority(),new ArrayList<TlsSrv>());
					}
					priorities.get(srv.getPriority()).add(new TlsSrv(srv, tls));
				} else if (d instanceof SRV) {
					Log.d(Config.LOGTAG,"found unrecognized SRV record with name: "+name);
				}
				if (d instanceof A) {
					A a = (A) d;
					if (!ips4.containsKey(name)) {
						ips4.put(name, new ArrayList<String>());
					}
					ips4.get(name).add(a.toString());
				}
				if (d instanceof AAAA) {
					AAAA aaaa = (AAAA) d;
					if (!ips6.containsKey(name)) {
						ips6.put(name, new ArrayList<String>());
					}
					ips6.get(name).add("[" + aaaa.toString() + "]");
				}
			}
		}
	}

	public static Bundle queryDNS(String host, InetAddress dnsServer) {
		Bundle bundle = new Bundle();
		try {
			client.setTimeout(Config.SOCKET_TIMEOUT * 1000);
			final String qname = "_xmpp-client._tcp." + host.toLowerCase(Locale.US);
			final String tlsQname = "_xmpps-client._tcp." + host.toLowerCase(Locale.US);
			Log.d(Config.LOGTAG, "using dns server: " + dnsServer.getHostAddress() + " to look up " + host);

			final Map<Integer, List<TlsSrv>> priorities = new TreeMap<>();
			final Map<String, List<String>> ips4 = new TreeMap<>();
			final Map<String, List<String>> ips6 = new TreeMap<>();

			fillSrvMaps(qname, dnsServer, priorities, ips4, ips6, false);
			fillSrvMaps(tlsQname, dnsServer, priorities, ips4, ips6, true);

			final List<TlsSrv> result = new ArrayList<>();
			for (final List<TlsSrv> s : priorities.values()) {
				result.addAll(s);
			}

			final ArrayList<Bundle> values = new ArrayList<>();
			if (result.size() == 0) {
				DNSMessage response;
				try {
					response = client.query(host, TYPE.A, CLASS.IN, dnsServer.getHostAddress());
					for (int i = 0; i < response.getAnswers().length; ++i) {
						values.add(createNamePortBundle(host, 5222, response.getAnswers()[i].getPayload(), false));
					}
				} catch (SocketTimeoutException e) {
					Log.d(Config.LOGTAG,"ignoring timeout exception when querying A record on "+dnsServer.getHostAddress());
				}
				try {
					response = client.query(host, TYPE.AAAA, CLASS.IN, dnsServer.getHostAddress());
					for (int i = 0; i < response.getAnswers().length; ++i) {
						values.add(createNamePortBundle(host, 5222, response.getAnswers()[i].getPayload(), false));
					}
				} catch (SocketTimeoutException e) {
					Log.d(Config.LOGTAG,"ignoring timeout exception when querying AAAA record on "+dnsServer.getHostAddress());
				}
				values.add(createNamePortBundle(host, 5222, false));
				bundle.putParcelableArrayList("values", values);
				return bundle;
			}
			for (final TlsSrv tlsSrv : result) {
				final SRV srv = tlsSrv.srv;
				final String name = srv.getName() != null ? srv.getName().toLowerCase(Locale.US) : null;
				if (ips6.containsKey(name)) {
					values.add(createNamePortBundle(name,srv.getPort(),ips6, tlsSrv.tls));
				} else {
					try {
						DNSMessage response = client.query(name, TYPE.AAAA, CLASS.IN, dnsServer.getHostAddress());
						for (int i = 0; i < response.getAnswers().length; ++i) {
							values.add(createNamePortBundle(name, srv.getPort(), response.getAnswers()[i].getPayload(), tlsSrv.tls));
						}
					} catch (SocketTimeoutException e) {
						Log.d(Config.LOGTAG,"ignoring timeout exception when querying AAAA record on "+dnsServer.getHostAddress());
					}
				}
				if (ips4.containsKey(name)) {
					values.add(createNamePortBundle(name,srv.getPort(),ips4, tlsSrv.tls));
				} else {
					DNSMessage response = client.query(name, TYPE.A, CLASS.IN, dnsServer.getHostAddress());
					for(int i = 0; i < response.getAnswers().length; ++i) {
						values.add(createNamePortBundle(name,srv.getPort(),response.getAnswers()[i].getPayload(), tlsSrv.tls));
					}
				}
				values.add(createNamePortBundle(name, srv.getPort(), tlsSrv.tls));
			}
			bundle.putParcelableArrayList("values", values);
		} catch (SocketTimeoutException e) {
			bundle.putString("error", "timeout");
		} catch (Exception e) {
			bundle.putString("error", "unhandled");
		}
		return bundle;
	}

	private static Bundle createNamePortBundle(String name, int port, final boolean tls) {
		Bundle namePort = new Bundle();
		namePort.putString("name", name);
		namePort.putBoolean("tls", tls);
		namePort.putInt("port", port);
		return namePort;
	}

	private static Bundle createNamePortBundle(String name, int port, Map<String, List<String>> ips, final boolean tls) {
		Bundle namePort = new Bundle();
		namePort.putString("name", name);
		namePort.putBoolean("tls", tls);
		namePort.putInt("port", port);
		if (ips!=null) {
			List<String> ip = ips.get(name);
			Collections.shuffle(ip, new Random());
			namePort.putString("ip", ip.get(0));
		}
		return namePort;
	}

	private static Bundle createNamePortBundle(String name, int port, Data data, final boolean tls) {
		Bundle namePort = new Bundle();
		namePort.putString("name", name);
		namePort.putBoolean("tls", tls);
		namePort.putInt("port", port);
		if (data instanceof A) {
			namePort.putString("ip", data.toString());
		} else if (data instanceof AAAA) {
			namePort.putString("ip","["+data.toString()+"]");
		}
		return namePort;
	}

	public static boolean isIp(final String server) {
		return server != null && (
				PATTERN_IPV4.matcher(server).matches()
				|| PATTERN_IPV6.matcher(server).matches()
				|| PATTERN_IPV6_6HEX4DEC.matcher(server).matches()
				|| PATTERN_IPV6_HEX4DECCOMPRESSED.matcher(server).matches()
				|| PATTERN_IPV6_HEXCOMPRESSED.matcher(server).matches());
	}
}

A src/main/java/eu/siacs/conversations/utils/IP.java => src/main/java/eu/siacs/conversations/utils/IP.java +22 -0
@@ 0,0 1,22 @@
package eu.siacs.conversations.utils;

import java.util.regex.Pattern;

public class IP {

    private static final Pattern PATTERN_IPV4 = Pattern.compile("\\A(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
    private static final Pattern PATTERN_IPV6_HEX4DECCOMPRESSED = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::((?:[0-9A-Fa-f]{1,4}:)*)(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
    private static final Pattern PATTERN_IPV6_6HEX4DEC = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}:){6,6})(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
    private static final Pattern PATTERN_IPV6_HEXCOMPRESSED = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)\\z");
    private static final Pattern PATTERN_IPV6 = Pattern.compile("\\A(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\z");

    public static boolean matches(String server) {
        return server != null && (
                PATTERN_IPV4.matcher(server).matches()
                        || PATTERN_IPV6.matcher(server).matches()
                        || PATTERN_IPV6_6HEX4DEC.matcher(server).matches()
                        || PATTERN_IPV6_HEX4DECCOMPRESSED.matcher(server).matches()
                        || PATTERN_IPV6_HEXCOMPRESSED.matcher(server).matches());
    }

}

A src/main/java/eu/siacs/conversations/utils/Resolver.java => src/main/java/eu/siacs/conversations/utils/Resolver.java +163 -0
@@ 0,0 1,163 @@
package eu.siacs.conversations.utils;

import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;

import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import de.measite.minidns.DNSClient;
import de.measite.minidns.DNSName;
import de.measite.minidns.Question;
import de.measite.minidns.Record;
import de.measite.minidns.hla.DnssecResolverApi;
import de.measite.minidns.hla.ResolverResult;
import de.measite.minidns.record.A;
import de.measite.minidns.record.AAAA;
import de.measite.minidns.record.Data;
import de.measite.minidns.record.InternetAddressRR;
import de.measite.minidns.record.SRV;
import eu.siacs.conversations.Config;

public class Resolver {

    private static final String DIRECT_TLS_SERVICE = "_xmpps-client";
    private static final String STARTTLS_SERICE = "_xmpp-client";




    public static void registerLookupMechanism(Context context) {
        DNSClient.addDnsServerLookupMechanism(new AndroidUsingLinkProperties(context));
    }

    public static List<Result> resolve(String domain) {
        List<Result> results = new ArrayList<>();
        try {
            results.addAll(resolveSrv(domain,true));
        } catch (IOException e) {
            //ignore
        }
        try {
            results.addAll(resolveSrv(domain,false));
        } catch (IOException e) {
            //ignore
        }
        if (results.size() == 0) {
            results.add(Result.createDefault(domain));
        }
        Collections.sort(results);
        return results;
    }

    private static List<Result> resolveSrv(String domain, final boolean directTls) throws IOException {
        Question question = new Question((directTls ? DIRECT_TLS_SERVICE : STARTTLS_SERICE)+"._tcp."+domain,Record.TYPE.SRV);
        ResolverResult<Data> result = DnssecResolverApi.INSTANCE.resolve(question);
        List<Result> results = new ArrayList<>();
        for(Data record : result.getAnswersOrEmptySet()) {
            if (record instanceof SRV) {
                SRV srvRecord = (SRV) record;
                boolean added = results.addAll(resolveIp(srvRecord,A.class,result.isAuthenticData(),directTls));
                added |= results.addAll(resolveIp(srvRecord,AAAA.class,result.isAuthenticData(),directTls));
                if (!added) {
                    Result resolverResult = Result.fromRecord(srvRecord, directTls);
                    resolverResult.authenticated = resolverResult.isAuthenticated();
                    results.add(resolverResult);
                }
            }
        }
        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 = DnssecResolverApi.INSTANCE.resolve(srv.name, type);
            for (D record : results.getAnswersOrEmptySet()) {
                Result resolverResult = Result.fromRecord(srv, directTls);
                resolverResult.authenticated = results.isAuthenticData() && authenticated;
                resolverResult.ip = record.getInetAddress();
                list.add(resolverResult);
            }
        } catch (IOException e) {
            Log.d(Config.LOGTAG,e.getMessage());
           //ignore. will add default record later
        }
        return list;
    }

    public static class Result implements Comparable<Result> {
        private InetAddress ip;
        private DNSName hostname;
        private int port = 5222;
        private boolean directTls = false;
        private boolean authenticated =false;
        private int priority;

        public InetAddress getIp() {
            return ip;
        }

        public int getPort() {
            return port;
        }

        public DNSName getHostname() {
            return hostname;
        }

        public boolean isDirectTls() {
            return directTls;
        }

        public boolean isAuthenticated() {
            return authenticated;
        }

        @Override
        public String toString() {
            return "Result{" +
                    "ip='" + ip + '\'' +
                    ", hostame='" + hostname.toString() + '\'' +
                    ", port=" + port +
                    ", directTls=" + directTls +
                    ", authenticated=" + authenticated +
                    ", priority=" + priority +
                    '}';
        }

        @Override
        public int compareTo(@NonNull Result result) {
            if (result.priority == priority) {
                if (directTls == result.directTls) {
                    return 0;
                } else {
                    return directTls ? 1 : -1;
                }
            } else {
                return priority - result.priority;
            }
        }

        public static Result fromRecord(SRV srv, boolean directTls) {
            Result result = new Result();
            result.port = srv.port;
            result.hostname = srv.name;
            result.directTls = directTls;
            result.priority = srv.priority;
            return result;
        }

        public static Result createDefault(String domain) {
            Result result = new Result();
            result.port = 5222;
            result.hostname = DNSName.from(domain);
            return result;
        }
    }

}

M src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java => src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +14 -25
@@ 2,8 2,6 @@ package eu.siacs.conversations.xmpp;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;


@@ 20,7 18,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.ConnectException;
import java.net.IDN;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;


@@ 67,8 64,9 @@ import eu.siacs.conversations.entities.ServiceDiscoveryResult;
import eu.siacs.conversations.generator.IqGenerator;
import eu.siacs.conversations.services.NotificationService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.DNSHelper;
import eu.siacs.conversations.utils.IP;
import eu.siacs.conversations.utils.Patterns;
import eu.siacs.conversations.utils.Resolver;
import eu.siacs.conversations.utils.SSLSocketHelper;
import eu.siacs.conversations.utils.SocksSocketFactory;
import eu.siacs.conversations.xml.Element;


@@ 329,7 327,7 @@ public class XmppConnection implements Runnable {
				} catch (Exception e) {
					throw new IOException(e.getMessage());
				}
			} else if (DNSHelper.isIp(account.getServer().toString())) {
			} else if (IP.matches(account.getServer().toString())) {
				localSocket = new Socket();
				try {
					localSocket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000);


@@ 345,37 343,28 @@ public class XmppConnection implements Runnable {
					throw new IOException(e.getMessage());
				}
			} else {
				final Bundle result = DNSHelper.getSRVRecord(account.getServer(), mXmppConnectionService);
				final ArrayList<Parcelable> values = result.getParcelableArrayList("values");
				for (Iterator<Parcelable> iterator = values.iterator(); iterator.hasNext(); ) {
				List<Resolver.Result> results = Resolver.resolve(account.getJid().getDomainpart());
				Log.d(Config.LOGTAG,"results: "+results);
				for (Iterator<Resolver.Result> iterator = results.iterator(); iterator.hasNext(); ) {
					final Resolver.Result result = iterator.next();
					if (Thread.currentThread().isInterrupted()) {
						Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": Thread was interrupted");
						return;
					}
					final Bundle namePort = (Bundle) iterator.next();
					try {
						String srvRecordServer;
						try {
							srvRecordServer = IDN.toASCII(namePort.getString("name"));
						} catch (final IllegalArgumentException e) {
							// TODO: Handle me?`
							srvRecordServer = "";
						}
						final int srvRecordPort = namePort.getInt("port");
						final String srvIpServer = namePort.getString("ip");
						// if tls is true, encryption is implied and must not be started
						features.encryptionEnabled = namePort.getBoolean("tls");
						features.encryptionEnabled = result.isDirectTls();
						final InetSocketAddress addr;
						if (srvIpServer != null) {
							addr = new InetSocketAddress(srvIpServer, srvRecordPort);
						if (result.getIp() != null) {
							addr = new InetSocketAddress(result.getIp(), result.getPort());
							Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
									+ ": using values from dns " + srvRecordServer
									+ "[" + srvIpServer + "]:" + srvRecordPort + " tls: " + features.encryptionEnabled);
									+ ": using values from dns " + result.getHostname().toString()
									+ "[" + result.getIp().toString() + "]:" + result.getPort() + " tls: " + features.encryptionEnabled);
						} else {
							addr = new InetSocketAddress(srvRecordServer, srvRecordPort);
							addr = new InetSocketAddress(result.getHostname().toString(), result.getPort());
							Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
									+ ": using values from dns "
									+ srvRecordServer + ":" + srvRecordPort + " tls: " + features.encryptionEnabled);
									+ result.getHostname().toString() + ":" + result.getPort() + " tls: " + features.encryptionEnabled);
						}

						if (!features.encryptionEnabled) {