Package org.eclipse.ecf.provider.dnssd

Source Code of org.eclipse.ecf.provider.dnssd.DnsSdDiscoveryAdvertiser

/*******************************************************************************
* Copyright (c) 2010 Markus Alexander Kuppe.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Markus Alexander Kuppe (ecf-dev_eclipse.org <at> lemmster <dot> de) - initial API and implementation
******************************************************************************/
package org.eclipse.ecf.provider.dnssd;

import java.io.EOFException;
import java.net.InetAddress;
import java.net.UnknownHostException;
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;
import org.eclipse.ecf.core.events.ContainerConnectedEvent;
import org.eclipse.ecf.core.events.ContainerConnectingEvent;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.identity.IDCreateException;
import org.eclipse.ecf.core.identity.IDFactory;
import org.eclipse.ecf.core.identity.Namespace;
import org.eclipse.ecf.core.security.IConnectContext;
import org.eclipse.ecf.core.util.Trace;
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;
import org.xbill.DNS.Type;
import org.xbill.DNS.Update;

public class DnsSdDiscoveryAdvertiser extends DnsSdDiscoveryContainerAdapter {
 
  private static final String _DNS_UPDATE = "_dns-update._udp."; //$NON-NLS-1$
  private static final boolean ADD = true;
  private static final boolean REMOVE = false;

  public DnsSdDiscoveryAdvertiser() {
    super(DnsSdNamespace.NAME, new DiscoveryContainerConfig(IDFactory
        .getDefault().createStringID(
            DnsSdDiscoveryAdvertiser.class.getName())));
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.ecf.provider.dnssd.DnsSdDiscoveryLocator#registerService(org.eclipse.ecf.discovery.IServiceInfo)
   */
  public void registerService(final IServiceInfo serviceInfo) {
    Trace.trace(Activator.PLUGIN_ID, DnsSdDebugOptions.METHODS_TRACING, this.getClass(), "registerService(IServiceInfo serviceInfo)", "Registering service"); //$NON-NLS-1$ //$NON-NLS-2$
    sendToServer(serviceInfo, ADD);
  }

  /* (non-Javadoc)
   * @see org.eclipse.ecf.provider.dnssd.DnsSdDiscoveryLocator#unregisterService(org.eclipse.ecf.discovery.IServiceInfo)
   */
  public void unregisterService(final IServiceInfo serviceInfo) {
    Trace.trace(Activator.PLUGIN_ID, DnsSdDebugOptions.METHODS_TRACING, this.getClass(), "unregisterService(IServiceInfo serviceInfo)", "Unregistering service"); //$NON-NLS-1$ //$NON-NLS-2$
    sendToServer(serviceInfo, REMOVE);
  }

  /* (non-Javadoc)
   * @see org.eclipse.ecf.discovery.AbstractDiscoveryContainerAdapter#unregisterAllServices()
   */
  public void unregisterAllServices() {
    Trace.trace(Activator.PLUGIN_ID, DnsSdDebugOptions.METHODS_TRACING, this.getClass(), "unregisterAllServices()", "Unregistering all services"); //$NON-NLS-1$ //$NON-NLS-2$
    throw new UnsupportedOperationException("Not yet implemented, see http://bugs.eclipse.org/321959"); //$NON-NLS-1$
  }

  /* (non-Javadoc)
   * @see org.eclipse.ecf.discovery.AbstractDiscoveryContainerAdapter#purgeCache()
   */
  public IServiceInfo[] purgeCache() {
    // purge cache means renew resolver?
    throw new UnsupportedOperationException("Not yet implemented, see http://bugs.eclipse.org/"); //$NON-NLS-1$
  }

  /* (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(final ID aTargetID, final IConnectContext connectContext)
      throws ContainerConnectException {

    Trace.trace(Activator.PLUGIN_ID, DnsSdDebugOptions.METHODS_TRACING, this.getClass(), "connect(ID aTargetID, IConnectContext connectContext)", "connecting container"); //$NON-NLS-1$ //$NON-NLS-2$

    // connect can only be called once
    if (targetID != null || getConfig() == null) {
      throw new ContainerConnectException(Messages.DnsSdDiscoveryAdvertiser_Container_Already_Connected);
    }

    //TODO convert non DnsSdServiceTypeIDs into DSTIDs
    if(aTargetID == null) {
      targetID = new DnsSdServiceTypeID();
    } else {
      final Namespace ns = getConnectNamespace();
      try {
        targetID = (DnsSdServiceTypeID) ns.createInstance(new Object[]{aTargetID});
      } catch(IDCreateException e) {
        throw new ContainerConnectException(e);
      }
    }
   
    // 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));
  }

  protected void sendToServer(final IServiceInfo serviceInfo, final boolean mode) {
    Assert.isNotNull(serviceInfo);
    Assert.isLegal(serviceInfo.getServiceID() instanceof DnsSdServiceID);
    final DnsSdServiceID serviceID = (DnsSdServiceID) serviceInfo.getServiceID();
    try {
      final Record srvRecord = serviceID.toSRVRecord(); // TYPE.SRV
      final Record[] txtRecords = serviceID.toTXTRecords(srvRecord); // TYPE.TXT
      final Name name = serviceID.getDnsName();
   
      final String[] registrationDomains = getRegistrationDomains(serviceID.getServiceTypeID());
   
      for (int i = 0; i < registrationDomains.length; i++) {
        final Name zone = new Name(registrationDomains[i]);
        final Name fqdn = new Name(name.toString() + "." + zone.toString()); //$NON-NLS-1$
        final Update update = new Update(zone);

        //TYPE.SRV
        if(mode == ADD) {
          //TODO add absent/present condition checks
          update.replace(srvRecord.withName(fqdn));
        } else {
          update.delete(srvRecord.withName(fqdn));
        }
       
        //TYPE.TXT
        for (int j = 0; j < txtRecords.length; j++) {
          if(mode == ADD) {
            update.add(txtRecords[j].withName(fqdn));
          } else {
            update.delete(txtRecords[j].withName(fqdn));
          }
        }
       
        // 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(Messages.DnsSdDiscoveryAdvertiser_No_DynDns_Servers_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) {
      throw new DnsSdDiscoveryException(e);
    }
  }

  protected Collection getUpdateDomain(final Name zone) throws TextParseException {
    Trace.trace(Activator.PLUGIN_ID, DnsSdDebugOptions.METHODS_TRACING, this.getClass(), "getUpdateDomain(Name zone)", "Getting update domain"); //$NON-NLS-1$ //$NON-NLS-2$
    // 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());

    // if no dedicated "_dns-update" server is configured, fall back to regular authoritative server
    if(srvRecords.size() == 0) {
      Trace.trace(Activator.PLUGIN_ID, DnsSdDebugOptions.METHODS_TRACING, this.getClass(), "getUpdateDomain(Name zone)", "Found no _dns-update SRV records in zone"); //$NON-NLS-1$ //$NON-NLS-2$
      return getAuthoritativeNameServer(zone);
    }
    return srvRecords;
  }
 
  protected Collection getAuthoritativeNameServer(final Name zone) throws TextParseException {
    Trace.trace(Activator.PLUGIN_ID, DnsSdDebugOptions.METHODS_TRACING, this.getClass(), "getAuthoritativeNameServer(Name zone)", "Trying to find authoritative name server"); //$NON-NLS-1$ //$NON-NLS-2$
    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);
    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++) {
      final Record record = queryResult[j];
      if(record instanceof NSRecord) {
        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));
      }
    }
   
    //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;
  }

  protected String[] getRegistrationDomains(final IServiceTypeID aServiceTypeId) {
    Trace.trace(Activator.PLUGIN_ID, DnsSdDebugOptions.METHODS_TRACING, this.getClass(), "getRegistrationDomains(IServiceTypeID aServiceTypeId)", "Getting registration domains"); //$NON-NLS-1$ //$NON-NLS-2$
    final String[] rrs = new String[] {BnRDnsSdServiceTypeID.REG_DOMAINS, BnRDnsSdServiceTypeID.DEFAULT_REG_DOMAIN};
    final Collection registrationDomains = getBrowsingOrRegistrationDomains(aServiceTypeId, rrs);
    final String[] scopes = aServiceTypeId.getScopes();
    for (int i = 0; i < scopes.length; i++) {
      scopes[i] = scopes[i].concat("."); //$NON-NLS-1$
    }
    return registrationDomains.size() == 0 ? scopes : (String[]) registrationDomains.toArray(new String[registrationDomains.size()]);
  }

  /* (non-Javadoc)
   * @see org.eclipse.ecf.discovery.AbstractDiscoveryContainerAdapter#getContainerName()
   */
  public String getContainerName() {
    return Activator.DISCOVERY_CONTAINER_NAME_VALUE + Activator.ADVERTISER;
  }
}
TOP

Related Classes of org.eclipse.ecf.provider.dnssd.DnsSdDiscoveryAdvertiser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.