summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Clayton <alex.clayton@isode.com>2016-07-13 15:42:34 (GMT)
committerAlex Clayton <alex.clayton@isode.com>2016-07-15 15:19:04 (GMT)
commit4e70a84a8a792cfeae96bf7a0cb4c9b549e44d29 (patch)
treeaf606f030af75a86dcb0187c20d6466b1501b851
parent8708b7b01cf4f36524bff3dc9aa5a7a6534ce221 (diff)
downloadstroke-4e70a84a8a792cfeae96bf7a0cb4c9b549e44d29.zip
stroke-4e70a84a8a792cfeae96bf7a0cb4c9b549e44d29.tar.bz2
Stop HostAddress constructor running DNS lookup.
When running the latest stroke against harrier android a NetworkOnMainThread exception was encountered. This was traced to the new constructor HostAddress(String) that was been called by Connector.start() method. The issue was dues to difference between the java code in stroke and the c++ code in swiften. In swiften the equivalent conde calls boost::asio::ip::address::from_string, which parses a string that may be an ipv4 or ipv6 address into an IP address object. If the string is not one of these then the object is left invalid. In the java code InetAddress.getByName(String name) is used instead. If this is an ipv4 or ipv6 address then it parses it into an InetAddress object. However if is not one of these it does a DNS lookup on the address. This was what was causing the error. To match the C++ the java code should only create an InetAddress if the input is an IP address, if not it should be left null. This was done by copying the IPv4 and IPv6 regexes in the Regex class in isode lib. The input to HostAddress(String) is checked against these if it matches InetAddress.getByName is called, otherwise address is set to null. Test-information: Ran unit tests in stroke they all pass. Ran code against android harrier, no longer fails. Ran against MLC (with updates for other changes in stroke api) it still passes. Change-Id: I1945c7c3cdfece8feb45b9196483131c0d9c4e7c
-rw-r--r--src/com/isode/stroke/network/HostAddress.java70
1 files changed, 64 insertions, 6 deletions
diff --git a/src/com/isode/stroke/network/HostAddress.java b/src/com/isode/stroke/network/HostAddress.java
index a8eea1b..dae2558 100644
--- a/src/com/isode/stroke/network/HostAddress.java
+++ b/src/com/isode/stroke/network/HostAddress.java
@@ -4,13 +4,14 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
/*
- * Copyright (c) 2010, Isode Limited, London, England.
+ * Copyright (c) 2010-2016, Isode Limited, London, England.
* All rights reserved.
*/
package com.isode.stroke.network;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.regex.Pattern;
public class HostAddress {
@@ -19,11 +20,15 @@ public class HostAddress {
}
public HostAddress(String address) {
- try {
- address_ = InetAddress.getByName(address);
- }
- catch (UnknownHostException e) {
- address_ = null;
+ // To match C++ code this should try and create a InetAddress
+ // if and only if the input is a IPv4 or IPv6 address.
+ if (isIPv4OrIPv6Address(address)) {
+ try {
+ address_ = InetAddress.getByName(address);
+ }
+ catch (UnknownHostException e) {
+ address_ = null;
+ }
}
}
@@ -86,4 +91,57 @@ public class HostAddress {
}
private InetAddress address_;
+
+ /**
+ * Indicates if the value is an IPv4 address in dot notation or
+ * an IPv6 address in hexadecimal notation
+ * @param value A string to test. If {@code null} result will
+ * be false.
+ * @return {@code true} if the string is an IPv4 address in dot
+ * notation, or a IPv6 address in hexadecimal notation.
+ */
+ private static boolean isIPv4OrIPv6Address(String value) {
+ if (value == null) {
+ return false;
+ }
+ if (ipv4Pattern.matcher(value).matches()) {
+ return true;
+ }
+ if (ipv6Pattern.matcher(value).matches()) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Regular expression for IPv4 address.
+ *
+ * @see <a href="http://www.mkyong.com/regular-expressions/how-to-validate-ip-address-with-regular-expression/"> web link</a>
+ */
+ private static final String ipv4Regex =
+ "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
+ /**
+ * A pattern that can be used to match an IPv4 address (e.g. "1.2.3.4").
+ *
+ */
+ private static final Pattern ipv4Pattern = Pattern.compile(ipv4Regex);
+
+ /**
+ * Regular expression for IPv6 address. Note that this needs to be
+ * compiled with the CASE_INSENSITIVE option.
+ */
+ private static final String ipv6Regex =
+ "^(((?=(?>.*?::)(?!.*::)))(::)?([0-9A-F]{1,4}::?){0,5}"
+ + "|([0-9A-F]{1,4}:){6})(\\2([0-9A-F]{1,4}(::?|$)){0,2}"
+ + "|((25[0-5]|(2[0-4]|1\\d|[1-9])?\\d)(\\.|$)){4}"
+ + "|[0-9A-F]{1,4}:[0-9A-F]{1,4})(?<![^:]:|\\.)\\z";
+
+ /**
+ * A pattern that can be used to match an IPv6 address (e.g. "3ffe:1900:4545:3:200:f8ff:fe21:67cf").
+ */
+ private static final Pattern ipv6Pattern = Pattern.compile(ipv6Regex, Pattern.CASE_INSENSITIVE);
+
}