13742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Copyright 2003-2005 Arthur van Hoff, Rick Blair
23742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Licensed under Apache License version 2.0
33742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Original license LGPL
43742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
53742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpackage javax.jmdns.impl.tasks.state;
63742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
73742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.IOException;
83742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Timer;
93742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Logger;
103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.DNSOutgoing;
123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.DNSQuestion;
133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.DNSRecord;
143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.JmDNSImpl;
153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.ServiceInfoImpl;
163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSConstants;
173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordClass;
183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordType;
193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSState;
203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/**
223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 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,
233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * it launches an Announcer.
243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * <p/>
253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 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.
263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */
273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpublic class Prober extends DNSStateTask {
283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    static Logger logger = Logger.getLogger(Prober.class.getName());
293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Prober(JmDNSImpl jmDNSImpl) {
313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        super(jmDNSImpl, defaultTTL());
323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.setTaskState(DNSState.PROBING_1);
343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.associate(DNSState.PROBING_1);
353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.tasks.DNSTask#getName()
403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getName() {
433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return "Prober(" + (this.getDns() != null ? this.getDns().getName() : "") + ")";
443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see java.lang.Object#toString()
493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String toString() {
523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return super.toString() + " state: " + this.getTaskState();
533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.tasks.DNSTask#start(java.util.Timer)
583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void start(Timer timer) {
613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        long now = System.currentTimeMillis();
623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (now - this.getDns().getLastThrottleIncrement() < DNSConstants.PROBE_THROTTLE_COUNT_INTERVAL) {
633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this.getDns().setThrottle(this.getDns().getThrottle() + 1);
643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } else {
653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this.getDns().setThrottle(1);
663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.getDns().setLastThrottleIncrement(now);
683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this.getDns().isAnnounced() && this.getDns().getThrottle() < DNSConstants.PROBE_THROTTLE_COUNT) {
703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            timer.schedule(this, JmDNSImpl.getRandom().nextInt(1 + DNSConstants.PROBE_WAIT_INTERVAL), DNSConstants.PROBE_WAIT_INTERVAL);
713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } else if (!this.getDns().isCanceling() && !this.getDns().isCanceled()) {
723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            timer.schedule(this, DNSConstants.PROBE_CONFLICT_INTERVAL, DNSConstants.PROBE_CONFLICT_INTERVAL);
733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean cancel() {
783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.removeAssociation();
793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return super.cancel();
813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.tasks.state.DNSStateTask#getTaskDescription()
863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getTaskDescription() {
893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return "probing";
903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.tasks.state.DNSStateTask#checkRunCondition()
953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected boolean checkRunCondition() {
983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return !this.getDns().isCanceling() && !this.getDns().isCanceled();
993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.tasks.state.DNSStateTask#createOugoing()
1043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected DNSOutgoing createOugoing() {
1073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
1083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.tasks.state.DNSStateTask#buildOutgoingForDNS(javax.jmdns.impl.DNSOutgoing)
1133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected DNSOutgoing buildOutgoingForDNS(DNSOutgoing out) throws IOException {
1163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        DNSOutgoing newOut = out;
1173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        newOut.addQuestion(DNSQuestion.newQuestion(this.getDns().getLocalHost().getName(), DNSRecordType.TYPE_ANY, DNSRecordClass.CLASS_IN, DNSRecordClass.NOT_UNIQUE));
1183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (DNSRecord answer : this.getDns().getLocalHost().answers(DNSRecordClass.NOT_UNIQUE, this.getTTL())) {
1193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            newOut = this.addAuthoritativeAnswer(newOut, answer);
1203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return newOut;
1223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.tasks.state.DNSStateTask#buildOutgoingForInfo(javax.jmdns.impl.ServiceInfoImpl, javax.jmdns.impl.DNSOutgoing)
1273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected DNSOutgoing buildOutgoingForInfo(ServiceInfoImpl info, DNSOutgoing out) throws IOException {
1303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        DNSOutgoing newOut = out;
1313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        newOut = this.addQuestion(newOut, DNSQuestion.newQuestion(info.getQualifiedName(), DNSRecordType.TYPE_ANY, DNSRecordClass.CLASS_IN, DNSRecordClass.NOT_UNIQUE));
1323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // 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
1333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        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()
1343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                .getName()));
1353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return newOut;
1363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.tasks.state.DNSStateTask#recoverTask(java.lang.Throwable)
1413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected void recoverTask(Throwable e) {
1443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.getDns().recover();
1453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.tasks.state.DNSStateTask#advanceTask()
1503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected void advanceTask() {
1533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.setTaskState(this.getTaskState().advance());
1543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (!this.getTaskState().isProbing()) {
1553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            cancel();
1563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this.getDns().startAnnouncer();
1583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman}