1// Copyright 2003-2005 Arthur van Hoff, Rick Blair
2// Licensed under Apache License version 2.0
3// Original license LGPL
4
5package javax.jmdns.impl.tasks.state;
6
7import java.io.IOException;
8import java.util.Timer;
9import java.util.logging.Logger;
10
11import javax.jmdns.impl.DNSOutgoing;
12import javax.jmdns.impl.DNSQuestion;
13import javax.jmdns.impl.DNSRecord;
14import javax.jmdns.impl.JmDNSImpl;
15import javax.jmdns.impl.ServiceInfoImpl;
16import javax.jmdns.impl.constants.DNSConstants;
17import javax.jmdns.impl.constants.DNSRecordClass;
18import javax.jmdns.impl.constants.DNSRecordType;
19import javax.jmdns.impl.constants.DNSState;
20
21/**
22 * 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,
23 * it launches an Announcer.
24 * <p/>
25 * 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.
26 */
27public class Prober extends DNSStateTask {
28    static Logger logger = Logger.getLogger(Prober.class.getName());
29
30    public Prober(JmDNSImpl jmDNSImpl) {
31        super(jmDNSImpl, defaultTTL());
32
33        this.setTaskState(DNSState.PROBING_1);
34        this.associate(DNSState.PROBING_1);
35    }
36
37    /*
38     * (non-Javadoc)
39     * @see javax.jmdns.impl.tasks.DNSTask#getName()
40     */
41    @Override
42    public String getName() {
43        return "Prober(" + (this.getDns() != null ? this.getDns().getName() : "") + ")";
44    }
45
46    /*
47     * (non-Javadoc)
48     * @see java.lang.Object#toString()
49     */
50    @Override
51    public String toString() {
52        return super.toString() + " state: " + this.getTaskState();
53    }
54
55    /*
56     * (non-Javadoc)
57     * @see javax.jmdns.impl.tasks.DNSTask#start(java.util.Timer)
58     */
59    @Override
60    public void start(Timer timer) {
61        long now = System.currentTimeMillis();
62        if (now - this.getDns().getLastThrottleIncrement() < DNSConstants.PROBE_THROTTLE_COUNT_INTERVAL) {
63            this.getDns().setThrottle(this.getDns().getThrottle() + 1);
64        } else {
65            this.getDns().setThrottle(1);
66        }
67        this.getDns().setLastThrottleIncrement(now);
68
69        if (this.getDns().isAnnounced() && this.getDns().getThrottle() < DNSConstants.PROBE_THROTTLE_COUNT) {
70            timer.schedule(this, JmDNSImpl.getRandom().nextInt(1 + DNSConstants.PROBE_WAIT_INTERVAL), DNSConstants.PROBE_WAIT_INTERVAL);
71        } else if (!this.getDns().isCanceling() && !this.getDns().isCanceled()) {
72            timer.schedule(this, DNSConstants.PROBE_CONFLICT_INTERVAL, DNSConstants.PROBE_CONFLICT_INTERVAL);
73        }
74    }
75
76    @Override
77    public boolean cancel() {
78        this.removeAssociation();
79
80        return super.cancel();
81    }
82
83    /*
84     * (non-Javadoc)
85     * @see javax.jmdns.impl.tasks.state.DNSStateTask#getTaskDescription()
86     */
87    @Override
88    public String getTaskDescription() {
89        return "probing";
90    }
91
92    /*
93     * (non-Javadoc)
94     * @see javax.jmdns.impl.tasks.state.DNSStateTask#checkRunCondition()
95     */
96    @Override
97    protected boolean checkRunCondition() {
98        return !this.getDns().isCanceling() && !this.getDns().isCanceled();
99    }
100
101    /*
102     * (non-Javadoc)
103     * @see javax.jmdns.impl.tasks.state.DNSStateTask#createOugoing()
104     */
105    @Override
106    protected DNSOutgoing createOugoing() {
107        return new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
108    }
109
110    /*
111     * (non-Javadoc)
112     * @see javax.jmdns.impl.tasks.state.DNSStateTask#buildOutgoingForDNS(javax.jmdns.impl.DNSOutgoing)
113     */
114    @Override
115    protected DNSOutgoing buildOutgoingForDNS(DNSOutgoing out) throws IOException {
116        DNSOutgoing newOut = out;
117        newOut.addQuestion(DNSQuestion.newQuestion(this.getDns().getLocalHost().getName(), DNSRecordType.TYPE_ANY, DNSRecordClass.CLASS_IN, DNSRecordClass.NOT_UNIQUE));
118        for (DNSRecord answer : this.getDns().getLocalHost().answers(DNSRecordClass.NOT_UNIQUE, this.getTTL())) {
119            newOut = this.addAuthoritativeAnswer(newOut, answer);
120        }
121        return newOut;
122    }
123
124    /*
125     * (non-Javadoc)
126     * @see javax.jmdns.impl.tasks.state.DNSStateTask#buildOutgoingForInfo(javax.jmdns.impl.ServiceInfoImpl, javax.jmdns.impl.DNSOutgoing)
127     */
128    @Override
129    protected DNSOutgoing buildOutgoingForInfo(ServiceInfoImpl info, DNSOutgoing out) throws IOException {
130        DNSOutgoing newOut = out;
131        newOut = this.addQuestion(newOut, DNSQuestion.newQuestion(info.getQualifiedName(), DNSRecordType.TYPE_ANY, DNSRecordClass.CLASS_IN, DNSRecordClass.NOT_UNIQUE));
132        // 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
133        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()
134                .getName()));
135        return newOut;
136    }
137
138    /*
139     * (non-Javadoc)
140     * @see javax.jmdns.impl.tasks.state.DNSStateTask#recoverTask(java.lang.Throwable)
141     */
142    @Override
143    protected void recoverTask(Throwable e) {
144        this.getDns().recover();
145    }
146
147    /*
148     * (non-Javadoc)
149     * @see javax.jmdns.impl.tasks.state.DNSStateTask#advanceTask()
150     */
151    @Override
152    protected void advanceTask() {
153        this.setTaskState(this.getTaskState().advance());
154        if (!this.getTaskState().isProbing()) {
155            cancel();
156
157            this.getDns().startAnnouncer();
158        }
159    }
160
161}