From 14a773c38050d4af9c34c24e426b7a5460ad9735 Mon Sep 17 00:00:00 2001 From: Nick Hudson Date: Fri, 18 Oct 2013 16:07:53 +0100 Subject: Re-implement DNS lookup to use dnsjava rather than JNDI There are limitations when using JNDI for DNS lookups, including that it does not properly handle the situation when resolv.conf contains IPv6 addresses (Isode bug #44832) - see e.g. http://java.net/jira/browse/JITSI-295 JNDI is also not readily available on Android, which makes it slightly more awkward to use Stroke on that platform. This patch changes the PlatformDomainName classes so that they use classes from dnsjava rather than JNDI. The patch also updates the build scripts so that dnsjava.jar is fetched (if necessary) and included in the build. Indentation in build.xml has been tidied up Test-information: Ran unit tests - ok Ran MLC - works OK and no longer throws NumberFormatExceptions when resolve.conf contains "nameserver 2001:470:f052::2" Change-Id: Iacf1105c52c281f9e59b60ea6caa011914b588dc diff --git a/Makefile b/Makefile index 778e5ca..770e231 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ all: dist/lib/stroke.jar -DEFINES = -Dxpp-dir=third-party/xpp -Djzlib-dir=third-party/jzlib -Dicu4j-dir=third-party/ -Dstax2-dir=third-party/stax2/ -Daalto-dir=third-party/aalto/ +DEFINES = -Dxpp-dir=third-party/xpp -Djzlib-dir=third-party/jzlib -Dicu4j-dir=third-party/ -Dstax2-dir=third-party/stax2/ -Daalto-dir=third-party/aalto/ -Ddnsjava-dir=third-party/dnsjava JUNIT ?= /usr/share/junit/junit.jar .PHONY : clean @@ -13,7 +13,7 @@ distclean: clean rm -rf third-party .PHONY : dist/lib/stroke.jar -dist/lib/stroke.jar: third-party/jzlib/jzlib.jar third-party/icu4j.jar third-party/aalto/aalto-xml.jar third-party/stax2/stax2-api.jar +dist/lib/stroke.jar: third-party/jzlib/jzlib.jar third-party/icu4j.jar third-party/aalto/aalto-xml.jar third-party/stax2/stax2-api.jar third-party/dnsjava/dnsjava.jar ant ${DEFINES} .PHONY : test @@ -40,6 +40,10 @@ third-party/icu4j.jar: mkdir -p third-party curl http://download.icu-project.org/files/icu4j/4.8.1/icu4j-4_8_1.jar -o third-party/icu4j.jar +third-party/dnsjava/dnsjava.jar: + mkdir -p third-party/dnsjava + curl http://www.dnsjava.org/download/dnsjava-2.1.6.jar -o third-party/dnsjava/dnsjava.jar + third-party/cobertura/cobertura.jar: mkdir -p third-party curl -L 'http://sourceforge.net/projects/cobertura/files/cobertura/1.9.4.1/cobertura-1.9.4.1-bin.tar.bz2/download' -o third-party/cobertura-1.9.4.1-bin.tar.bz2 diff --git a/README b/README index 3aa671e..0574db7 100644 --- a/README +++ b/README @@ -9,6 +9,8 @@ It also depends upon http://www.jcraft.com/jzlib/, which is passed to ant in the It also depends upon icu4j from http://site.icu-project.org/ +It also depends upon dnsjava from http://www.dnsjava.org/ + To build, run: ant -Dxpp-dir=third-party/xpp -Djzlib-dir=third-party/jzlib -Dicu4j-dir=third-party/ -Dstax2-dir=third-party/stax2/ -Daalto-dir=third-party/aalto/ diff --git a/build.xml b/build.xml index 7fe424c..6c4058f 100644 --- a/build.xml +++ b/build.xml @@ -1,5 +1,5 @@ @@ -20,16 +20,17 @@ + - - - - - + + + + + @@ -38,6 +39,7 @@ + @@ -92,7 +94,7 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + @@ -190,7 +191,7 @@ + description="clean up" > @@ -210,18 +211,18 @@ - + - - - - - - + + + + + + diff --git a/src/com/isode/stroke/network/PlatformDomainNameResolver.java b/src/com/isode/stroke/network/PlatformDomainNameResolver.java index 3eef682..32f466d 100644 --- a/src/com/isode/stroke/network/PlatformDomainNameResolver.java +++ b/src/com/isode/stroke/network/PlatformDomainNameResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012, Isode Limited, London, England. + * Copyright (c) 2010-2013, Isode Limited, London, England. * All rights reserved. */ /* @@ -16,6 +16,8 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; +import org.xbill.DNS.Address; + public class PlatformDomainNameResolver extends DomainNameResolver { private class AddressQuery extends DomainNameAddressQuery implements EventOwner { @@ -25,10 +27,11 @@ public class PlatformDomainNameResolver extends DomainNameResolver { public void run() { final Collection results = new ArrayList(); try { - for (InetAddress result : InetAddress.getAllByName(hostname)) { + for (InetAddress result : Address.getAllByName(hostname)) { results.add(new HostAddress(result)); } } catch (UnknownHostException ex) { + /* results remains empty */ } eventLoop.postEvent(new Callback() { public void run() { @@ -53,17 +56,17 @@ public class PlatformDomainNameResolver extends DomainNameResolver { } public PlatformDomainNameResolver(EventLoop eventLoop) { - this.eventLoop = eventLoop; + this.eventLoop_ = eventLoop; } @Override public DomainNameServiceQuery createServiceQuery(String name) { - return new PlatformDomainNameServiceQuery(getNormalized(name), eventLoop); + return new PlatformDomainNameServiceQuery(getNormalized(name), eventLoop_); } @Override public DomainNameAddressQuery createAddressQuery(String name) { - return new AddressQuery(getNormalized(name), eventLoop); + return new AddressQuery(getNormalized(name), eventLoop_); } - private final EventLoop eventLoop; + private final EventLoop eventLoop_; } diff --git a/src/com/isode/stroke/network/PlatformDomainNameServiceQuery.java b/src/com/isode/stroke/network/PlatformDomainNameServiceQuery.java index 0fc7976..37cf1f2 100644 --- a/src/com/isode/stroke/network/PlatformDomainNameServiceQuery.java +++ b/src/com/isode/stroke/network/PlatformDomainNameServiceQuery.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012, Isode Limited, London, England. + * Copyright (c) 2010-2013, Isode Limited, London, England. * All rights reserved. */ /* @@ -9,79 +9,69 @@ */ package com.isode.stroke.network; +import java.util.ArrayList; +import java.util.Collection; + +import org.xbill.DNS.Lookup; +import org.xbill.DNS.Record; +import org.xbill.DNS.SRVRecord; +import org.xbill.DNS.TextParseException; +import org.xbill.DNS.Type; import com.isode.stroke.eventloop.Event.Callback; import com.isode.stroke.eventloop.EventLoop; -import com.isode.stroke.eventloop.EventOwner; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Hashtable; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.InitialDirContext; +import com.isode.stroke.network.DomainNameServiceQuery; -public class PlatformDomainNameServiceQuery extends DomainNameServiceQuery implements EventOwner { +public class PlatformDomainNameServiceQuery extends DomainNameServiceQuery { + private final String service; + private final EventLoop eventLoop; - private class QueryThread extends Thread { + public PlatformDomainNameServiceQuery(final String service, final EventLoop eventLoop) { + this.service = service; + this.eventLoop = eventLoop; + } + private class QueryThread extends Thread { @Override public void run() { final Collection results = new ArrayList(); - Hashtable env = new Hashtable(); - env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory"); - env.put("java.naming.provider.url", "dns:"); - DirContext ctx = null; + Lookup request; try { - ctx = new InitialDirContext(env); - Attributes attrs = ctx.getAttributes(service, new String[]{"SRV"}); - Attribute attribute = attrs.get("SRV"); - for (int i = 0; attribute != null && i < attribute.size(); i++) { - /* SRV results are going to be returned in the space-separated format - * Priority Weight Port Target - * (See RFC2782) - */ - String[] srvParts = ((String) attribute.get(i)).split(" "); - String host = srvParts[3]; - if (host.endsWith(".")) { - host = host.substring(0, host.length() - 1); + request = new Lookup(service, Type.SRV); + final Record[] records = request.run(); + if (records != null) { + for (final Record record : records) { + /* It's only anticipated that SRVRecords will be + * returned, but check first + */ + if (record instanceof SRVRecord) { + final SRVRecord srv = (SRVRecord) record; + final Result result = new Result(srv.getTarget() + .toString(), srv.getPort(), srv.getPriority(), + srv.getWeight()); + results.add(result); + } } - Result result = new Result(host, Integer.parseInt(srvParts[2]), Integer.parseInt(srvParts[0]), Integer.parseInt(srvParts[1])); - results.add(result); } - } catch (NamingException ex) { - /* Turns out that you get the exception just for not finding a result, so we want to fall through to A lookups and ignore.*/ + } catch (final TextParseException e) { + /* Lookup failed because "service" was not a valid DNS name; + * leave "results" empty + */ } eventLoop.postEvent(new Callback() { + @Override public void run() { onResult.emit(results); } }); - //close the context as otherwise this will lead to open sockets in - //CLOSE_WAIT condition - if(ctx != null) { - try { - ctx.close(); - } catch (NamingException e) { - //at least we try to close the context - } - } } } - public PlatformDomainNameServiceQuery(String service, EventLoop eventLoop) { - this.service = service; - this.eventLoop = eventLoop; - } - @Override public void run() { - QueryThread thread = new QueryThread(); + final QueryThread thread = new QueryThread(); thread.setDaemon(true); thread.start(); } - private final String service; - private final EventLoop eventLoop; } -- cgit v0.10.2-6-g49f6