diff options
| author | Markus Alexander Kuppe | 2010-07-19 12:15:21 +0000 |
|---|---|---|
| committer | Markus Alexander Kuppe | 2010-07-19 12:15:21 +0000 |
| commit | dfc694630adf60cd9663bc15f2adca40a232be82 (patch) | |
| tree | b0949970a42900a2ed000c1e8d81708d196e258e | |
| parent | ea1668ebb04ef26cdc5864c8f2d84bbef9943ec3 (diff) | |
| download | org.eclipse.ecf-dfc694630adf60cd9663bc15f2adca40a232be82.tar.gz org.eclipse.ecf-dfc694630adf60cd9663bc15f2adca40a232be82.tar.xz org.eclipse.ecf-dfc694630adf60cd9663bc15f2adca40a232be82.zip | |
NEW - bug 320188: [Discovery][DNS-SD] IDiscoveryAdvertiser must use registration domains
https://bugs.eclipse.org/bugs/show_bug.cgi?id=320188
3 files changed, 188 insertions, 82 deletions
diff --git a/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryAdvertiser.java b/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryAdvertiser.java index 494bef12e..b416adbc9 100644 --- a/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryAdvertiser.java +++ b/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryAdvertiser.java @@ -10,9 +10,14 @@ ******************************************************************************/ package org.eclipse.ecf.provider.dnssd; +import java.io.EOFException; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.List; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.SortedSet; import org.eclipse.core.runtime.Assert; import org.eclipse.ecf.core.ContainerConnectException; @@ -24,12 +29,14 @@ import org.eclipse.ecf.core.security.IConnectContext; import org.eclipse.ecf.discovery.DiscoveryContainerConfig; import org.eclipse.ecf.discovery.IServiceInfo; import org.eclipse.ecf.discovery.identity.IServiceTypeID; +import org.xbill.DNS.DClass; import org.xbill.DNS.Lookup; import org.xbill.DNS.Message; import org.xbill.DNS.NSRecord; import org.xbill.DNS.Name; import org.xbill.DNS.Rcode; import org.xbill.DNS.Record; +import org.xbill.DNS.SOARecord; import org.xbill.DNS.SRVRecord; import org.xbill.DNS.SimpleResolver; import org.xbill.DNS.TextParseException; @@ -38,6 +45,7 @@ import org.xbill.DNS.Update; public class DnsSdDiscoveryAdvertiser extends DnsSdDiscoveryContainerAdapter { + private static final String _DNS_UPDATE = "_dns-update._udp."; private static final boolean ADD = true; private static final boolean REMOVE = false; @@ -61,6 +69,55 @@ public class DnsSdDiscoveryAdvertiser extends DnsSdDiscoveryContainerAdapter { sendToServer(serviceInfo, REMOVE); } + /* (non-Javadoc) + * @see org.eclipse.ecf.discovery.AbstractDiscoveryContainerAdapter#unregisterAllServices() + */ + public void unregisterAllServices() { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.discovery.AbstractDiscoveryContainerAdapter#purgeCache() + */ + public IServiceInfo[] purgeCache() { + // purge cache means renew resolver? + throw new UnsupportedOperationException("Not yet implemented"); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.provider.dnssd.DnsSdDiscoveryLocator#connect(org.eclipse.ecf.core.identity.ID, org.eclipse.ecf.core.security.IConnectContext) + */ + public void connect(ID aTargetID, IConnectContext connectContext) + throws ContainerConnectException { + + // connect can only be called once + if (targetID != null || getConfig() == null) { + throw new ContainerConnectException("Already connected"); + } + + //TODO convert non DnsSdServiceTypeIDs into DSTIDs + if(aTargetID == null) { + targetID = new DnsSdServiceTypeID(); + } else { + targetID = (DnsSdServiceTypeID) aTargetID; + } + + // instantiate a default resolver + if(resolver == null) { + try { + resolver = new SimpleResolver(); + resolver.setTCP(true); + } catch (UnknownHostException e) { + throw new ContainerConnectException(e); + } + } + + // done setting up this provider, send event + fireContainerEvent(new ContainerConnectingEvent(this.getID(), targetID, + connectContext)); + fireContainerEvent(new ContainerConnectedEvent(this.getID(), targetID)); + } + private void sendToServer(final IServiceInfo serviceInfo, final boolean mode) { Assert.isNotNull(serviceInfo); final DnsSdServiceID serviceID = (DnsSdServiceID) serviceInfo.getServiceID(); @@ -93,12 +150,47 @@ public class DnsSdDiscoveryAdvertiser extends DnsSdDiscoveryContainerAdapter { } } - // set up a new resolver for the given domain (a scope might use different domains) - ((SimpleResolver) resolver).setAddress(getUpdateDomain(zone)); - resolver.setTCP(true); - final Message response = resolver.send(update); - if(response.getRcode() != Rcode.NOERROR) { - throw DnsSdDiscoveryException.getException(response.getRcode()); + // set up a the resolver for the given domain (a scope might use different domains) + final Collection dnsServers = getUpdateDomain(zone); + if(dnsServers.size() == 0) { + throw new DnsSdDiscoveryException("No server for dnsupdate could be found"); + } + for (final Iterator iterator = dnsServers.iterator(); iterator.hasNext();) { + final SRVRecord dnsServer = (SRVRecord) iterator.next(); + + // try to send msg and fail gracefully if more dns servers are available + final Name target = dnsServer.getTarget(); + final Message response; + final InetAddress byName; + try { + byName = InetAddress.getByName(target.toString()); + + ((SimpleResolver) resolver).setAddress(byName); + ((SimpleResolver) resolver).setPort(dnsServer.getPort()); + + response = resolver.send(update); + } catch (UnknownHostException uhe) { + if(iterator.hasNext()) { + continue; + } else { + throw new DnsSdDiscoveryException(uhe); + } + } catch (EOFException eof) { + if(iterator.hasNext()) { + continue; + } else { + throw new DnsSdDiscoveryException(eof); + } + } + + // catch some errors and fall back to the next dnsServer + if (response.getRcode() != Rcode.NOERROR) { + if(iterator.hasNext()) { + continue; + } else { + throw DnsSdDiscoveryException.getException(response.getRcode()); + } + } } } } catch (Exception e) { @@ -106,38 +198,66 @@ public class DnsSdDiscoveryAdvertiser extends DnsSdDiscoveryContainerAdapter { } } - private InetAddress getUpdateDomain(final Name zone) throws TextParseException, UnknownHostException { - //TODO check if ._udp has to be prepended - Lookup query = new Lookup("_dns-update._udp." + zone, Type.SRV); - List srvRecords = getSRVRecord(query); - if(srvRecords.size() > 0) { - //TODO use the first one returned for the moment, use prio/weight later - SRVRecord srvRecord = (SRVRecord) srvRecords.get(0); - srvRecord.getTarget(); - srvRecord.getPort(); - return null; + private Collection getUpdateDomain(final Name zone) throws TextParseException { + // query for special "_dns-update" SRV records which mark the server to use for dyndns + final Lookup query = new Lookup(_DNS_UPDATE + zone, Type.SRV); + // use the SRV record with the lowest priority/weight first + final SortedSet srvRecords = getSRVRecord(query, new SRVRecordComparator()); +// +// int prio = Integer.MAX_VALUE, weight = Integer.MAX_VALUE; +// for (Iterator iterator = srvRecords.iterator(); iterator.hasNext();) { +// final SRVRecord srvRecord = (SRVRecord) iterator.next(); +// if(srvRecord.getPriority() < prio) { +// if (srvRecord.getWeight() < weight) { +// prio = srvRecord.getPriority(); +// weight = srvRecord.getPriority(); +// result.add(new URI("dns://" + srvRecord.getTarget() + ":" + srvRecord.getPort())); +// } +// } +// } + + // if no dedicated "_dns-update" server is configured, fall back to regular authoritative server + if(srvRecords.size() == 0) { + return getAuthoritativeNameServer(zone); } - return getAuthoritiveNameServer(zone); + return srvRecords; } - private InetAddress getAuthoritiveNameServer(final Name zone) throws UnknownHostException { - final Lookup query = new Lookup(zone, Type.NS); + private Collection getAuthoritativeNameServer(final Name zone) throws TextParseException { + final Set result = new HashSet(); + final Name name = new Name(_DNS_UPDATE + zone); + + //query for NS records + Lookup query = new Lookup(zone, Type.NS); query.setResolver(resolver); - final Record[] queryResult = query.run(); + Record[] queryResult = query.run(); //TODO file bug upstream that queryResult may never be null int length = queryResult == null ? 0 : queryResult.length; for (int j = 0; j < length; j++) { - Record record = queryResult[j]; + final Record record = queryResult[j]; if(record instanceof NSRecord) { - NSRecord nsRecord = (NSRecord) record; - Name target = nsRecord.getTarget(); - return InetAddress.getByName(target.toString()); + final NSRecord nsRecord = (NSRecord) record; + final Name target = nsRecord.getTarget(); + result.add(new SRVRecord(name, DClass.IN, nsRecord.getTTL(), 0, 0, SimpleResolver.DEFAULT_PORT, target)); } } - return null; + + //query for primary ns in SOA record (may overwrite/be equal to one of the ns records) + query = new Lookup(zone, Type.SOA); + query.setResolver(resolver); + queryResult = query.run(); + //TODO file bug upstream that queryResult may never be null + length = queryResult == null ? 0 : queryResult.length; + for (int j = 0; j < length; j++) { + final Record record = queryResult[j]; + if(record instanceof SOARecord) { + final SOARecord soaRecord = (SOARecord) record; + result.add(new SRVRecord(name, DClass.IN, soaRecord.getTTL(), 0, 0, SimpleResolver.DEFAULT_PORT, soaRecord.getHost())); + } + } + return result; } - private String[] getRegistrationDomains(IServiceTypeID aServiceTypeId) { String[] rrs = new String[] {BnRDnsSdServiceTypeID.REG_DOMAINS, BnRDnsSdServiceTypeID.DEFAULT_REG_DOMAIN}; final String[] registrationDomains = getBrowsingOrRegistrationDomains(aServiceTypeId, rrs); @@ -147,52 +267,4 @@ public class DnsSdDiscoveryAdvertiser extends DnsSdDiscoveryContainerAdapter { } return registrationDomains.length == 0 ? scopes : registrationDomains; } - - /* (non-Javadoc) - * @see org.eclipse.ecf.discovery.AbstractDiscoveryContainerAdapter#unregisterAllServices() - */ - public void unregisterAllServices() { - throw new UnsupportedOperationException("Not yet implemented"); - } - - /* (non-Javadoc) - * @see org.eclipse.ecf.discovery.AbstractDiscoveryContainerAdapter#purgeCache() - */ - public IServiceInfo[] purgeCache() { - // purge cache means renew resolver? - throw new UnsupportedOperationException("Not yet implemented"); - } - - /* (non-Javadoc) - * @see org.eclipse.ecf.provider.dnssd.DnsSdDiscoveryLocator#connect(org.eclipse.ecf.core.identity.ID, org.eclipse.ecf.core.security.IConnectContext) - */ - public void connect(ID aTargetID, IConnectContext connectContext) - throws ContainerConnectException { - - // connect can only be called once - if (targetID != null || getConfig() == null) { - throw new ContainerConnectException("Already connected"); - } - - //TODO convert non DnsSdServiceTypeIDs into DSTIDs - if(aTargetID == null) { - targetID = new DnsSdServiceTypeID(); - } else { - targetID = (DnsSdServiceTypeID) aTargetID; - } - - // instantiate a default resolver - if(resolver == null) { - try { - resolver = new SimpleResolver(); - } catch (UnknownHostException e) { - throw new ContainerConnectException(e); - } - } - - // done setting up this provider, send event - fireContainerEvent(new ContainerConnectingEvent(this.getID(), targetID, - connectContext)); - fireContainerEvent(new ContainerConnectedEvent(this.getID(), targetID)); - } } diff --git a/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryContainerAdapter.java b/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryContainerAdapter.java index 00b489c88..d9c8853e6 100644 --- a/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryContainerAdapter.java +++ b/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryContainerAdapter.java @@ -13,9 +13,12 @@ package org.eclipse.ecf.provider.dnssd; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import org.eclipse.core.runtime.Assert; import org.eclipse.ecf.core.ContainerConnectException; @@ -167,16 +170,20 @@ public abstract class DnsSdDiscoveryContainerAdapter extends return (Record[]) result.toArray(new Record[result.size()]); } - protected List getSRVRecords(Lookup[] queries) { - List srvRecords = new ArrayList(); + protected SortedSet getSRVRecords(Lookup[] queries) { + return getSRVRecords(queries, null); + } + + protected SortedSet getSRVRecords(Lookup[] queries, Comparator aComparator) { + final SortedSet srvRecords = new TreeSet(aComparator); for (int i = 0; i < queries.length; i++) { - srvRecords.addAll(getSRVRecord(queries[i])); + srvRecords.addAll(getSRVRecord(queries[i], aComparator)); } return srvRecords; } - protected List getSRVRecord(Lookup query) { - final List srvRecords = new ArrayList(); + protected SortedSet getSRVRecord(Lookup query, Comparator aComparator) { + final SortedSet srvRecords = new TreeSet(aComparator); query.setResolver(resolver); final Record[] queryResult = query.run(); //TODO file bug upstream that queryResult may never be null @@ -198,6 +205,32 @@ public abstract class DnsSdDiscoveryContainerAdapter extends return srvRecords; } + // compares SRV records based on priority and weight + protected class SRVRecordComparator implements Comparator { + + /* (non-Javadoc) + * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) + */ + public int compare(Object arg0, Object arg1) { + if(arg0 instanceof SRVRecord && arg1 instanceof SRVRecord) { + SRVRecord srv1 = (SRVRecord) arg0; + SRVRecord srv2 = (SRVRecord) arg1; + if(srv1.getPriority() > srv2.getPriority()) { + return 1; + } else if (srv1.getPriority() == srv2.getPriority()) { + if(srv1.getWeight() > srv2.getWeight()) { + return 1; + } + return -1; + } else { + return -1; + } + } + throw new UnsupportedOperationException("This appears to be a bug: Comparator can only compare SRVRecords"); + } + + } + /** * @param searchPaths The default search path used for discovery */ diff --git a/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryLocator.java b/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryLocator.java index 691aa3456..ddc96392c 100644 --- a/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryLocator.java +++ b/providers/bundles/org.eclipse.ecf.provider.dnssd/src/org/eclipse/ecf/provider/dnssd/DnsSdDiscoveryLocator.java @@ -13,6 +13,7 @@ package org.eclipse.ecf.provider.dnssd; import java.net.URI; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Properties; @@ -119,12 +120,12 @@ public class DnsSdDiscoveryLocator extends DnsSdDiscoveryContainerAdapter { public IServiceInfo[] getServices(IServiceTypeID aServiceTypeId) { Assert.isNotNull(aServiceTypeId); DnsSdServiceTypeID serviceTypeId = (DnsSdServiceTypeID) aServiceTypeId; - List srvRecords = getSRVRecords(serviceTypeId.getInternalQueries()); + Collection srvRecords = getSRVRecords(serviceTypeId.getInternalQueries()); List serviceInfos = getServiceInfos(srvRecords); return (IServiceInfo[]) serviceInfos.toArray(new IServiceInfo[serviceInfos.size()]); } - private List getServiceInfos(List srvQueryResult) { + private List getServiceInfos(Collection srvQueryResult) { List infos = new ArrayList(); for (Iterator iterator = srvQueryResult.iterator(); iterator.hasNext();) { SRVRecord srvRecord = (SRVRecord) iterator.next(); |
