// Copyright 2003-2005 Arthur van Hoff, Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL
package javax.jmdns.impl.tasks.state;
import java.io.IOException;
import java.util.Timer;
import java.util.logging.Logger;
import javax.jmdns.impl.DNSOutgoing;
import javax.jmdns.impl.DNSQuestion;
import javax.jmdns.impl.DNSRecord;
import javax.jmdns.impl.JmDNSImpl;
import javax.jmdns.impl.ServiceInfoImpl;
import javax.jmdns.impl.constants.DNSConstants;
import javax.jmdns.impl.constants.DNSRecordClass;
import javax.jmdns.impl.constants.DNSRecordType;
import javax.jmdns.impl.constants.DNSState;
/**
* The Prober sends three consecutive probes for all service infos that needs
* probing as well as for the host name. The state of each service info of the
* host name is advanced, when a probe has been sent for it. When the prober has
* run three times, it launches an Announcer.
* <p/>
* If a conflict during probes occurs, the affected service infos (and affected
* host name) are taken away from the prober. This eventually causes the prober
* to cancel itself.
*/
public class Prober extends DNSStateTask
{
static Logger logger = Logger.getLogger(Prober.class.getName());
public Prober(JmDNSImpl jmDNSImpl)
{
super(jmDNSImpl, defaultTTL());
this.setTaskState(DNSState.PROBING_1);
this.associate(DNSState.PROBING_1);
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.tasks.DNSTask#getName()
*/
@Override
public String getName()
{
return "Prober(" + (this.getDns() != null ? this.getDns().getName() : "") + ")";
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return super.toString() + " state: " + this.getTaskState();
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.tasks.DNSTask#start(java.util.Timer)
*/
@Override
public void start(Timer timer)
{
long now = System.currentTimeMillis();
if (now - this.getDns().getLastThrottleIncrement() < DNSConstants.PROBE_THROTTLE_COUNT_INTERVAL)
{
this.getDns().setThrottle(this.getDns().getThrottle() + 1);
}
else
{
this.getDns().setThrottle(1);
}
this.getDns().setLastThrottleIncrement(now);
if (this.getDns().isAnnounced()
&& this.getDns().getThrottle() < DNSConstants.PROBE_THROTTLE_COUNT)
{
timer.schedule(this,
JmDNSImpl.getRandom().nextInt(1 + DNSConstants.PROBE_WAIT_INTERVAL),
DNSConstants.PROBE_WAIT_INTERVAL);
}
else if (!this.getDns().isCanceling() && !this.getDns().isCanceled())
{
timer.schedule(this, DNSConstants.PROBE_CONFLICT_INTERVAL,
DNSConstants.PROBE_CONFLICT_INTERVAL);
}
}
@Override
public boolean cancel()
{
this.removeAssociation();
return super.cancel();
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.tasks.state.DNSStateTask#getTaskDescription()
*/
@Override
public String getTaskDescription()
{
return "probing";
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.tasks.state.DNSStateTask#checkRunCondition()
*/
@Override
protected boolean checkRunCondition()
{
return !this.getDns().isCanceling() && !this.getDns().isCanceled();
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.tasks.state.DNSStateTask#createOugoing()
*/
@Override
protected DNSOutgoing createOugoing()
{
return new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
}
/*
* (non-Javadoc)
*
* @see
* javax.jmdns.impl.tasks.state.DNSStateTask#buildOutgoingForDNS(javax.jmdns
* .impl.DNSOutgoing)
*/
@Override
protected DNSOutgoing buildOutgoingForDNS(DNSOutgoing out) throws IOException
{
DNSOutgoing newOut = out;
newOut.addQuestion(DNSQuestion.newQuestion(
this.getDns().getLocalHost().getName(), DNSRecordType.TYPE_ANY,
DNSRecordClass.CLASS_IN, DNSRecordClass.NOT_UNIQUE));
for (DNSRecord answer : this
.getDns()
.getLocalHost()
.answers(DNSRecordClass.CLASS_ANY, DNSRecordClass.NOT_UNIQUE,
this.getTTL()))
{
newOut = this.addAuthoritativeAnswer(newOut, answer);
}
return newOut;
}
/*
* (non-Javadoc)
*
* @see
* javax.jmdns.impl.tasks.state.DNSStateTask#buildOutgoingForInfo(javax.
* jmdns.impl.ServiceInfoImpl, javax.jmdns.impl.DNSOutgoing)
*/
@Override
protected DNSOutgoing buildOutgoingForInfo(ServiceInfoImpl info, DNSOutgoing out)
throws IOException
{
DNSOutgoing newOut = out;
newOut = this.addQuestion(newOut, DNSQuestion.newQuestion(
info.getQualifiedName(), DNSRecordType.TYPE_ANY, DNSRecordClass.CLASS_IN,
DNSRecordClass.NOT_UNIQUE));
// the "unique" flag should be not set here because these answers haven't been proven unique yet this means the record will not exactly match the announcement record
newOut = this.addAuthoritativeAnswer(
newOut,
new DNSRecord.Service(info.getQualifiedName(), DNSRecordClass.CLASS_IN,
DNSRecordClass.NOT_UNIQUE, this.getTTL(), info.getPriority(), info
.getWeight(), info.getPort(), this.getDns().getLocalHost()
.getName()));
return newOut;
}
/*
* (non-Javadoc)
*
* @see
* javax.jmdns.impl.tasks.state.DNSStateTask#recoverTask(java.lang.Throwable
* )
*/
@Override
protected void recoverTask(Throwable e)
{
this.getDns().recover();
}
/*
* (non-Javadoc)
*
* @see javax.jmdns.impl.tasks.state.DNSStateTask#advanceTask()
*/
@Override
protected void advanceTask()
{
this.setTaskState(this.getTaskState().advance());
if (!this.getTaskState().isProbing())
{
cancel();
this.getDns().startAnnouncer();
}
}
}