-
Notifications
You must be signed in to change notification settings - Fork 231
/
Resolver.java
254 lines (234 loc) · 8.25 KB
/
Resolver.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package org.xbill.DNS;
import java.io.IOException;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Interface describing a resolver.
*
* @author Brian Wellington
*/
public interface Resolver {
/**
* Sets the port to communicate with on the server
*
* @param port The port to send messages to
*/
void setPort(int port);
/**
* Sets whether TCP connections will be used by default
*
* @param flag Indicates whether TCP connections are made
*/
void setTCP(boolean flag);
/**
* Sets whether truncated responses will be ignored. If not, a truncated response over UDP will
* cause a retransmission over TCP.
*
* @param flag Indicates whether truncated responses should be ignored.
*/
void setIgnoreTruncation(boolean flag);
/**
* Sets the EDNS version used on outgoing messages.
*
* @param version The EDNS level to use. 0 indicates EDNS0 and -1 indicates no EDNS.
* @throws IllegalArgumentException An invalid level was indicated.
*/
default void setEDNS(int version) {
setEDNS(version, 0, 0, Collections.emptyList());
}
/**
* Sets the EDNS information on outgoing messages.
*
* @param version The EDNS version to use. 0 indicates EDNS0 and -1 indicates no EDNS.
* @param payloadSize The maximum DNS packet size that this host is capable of receiving over UDP.
* If 0 is specified, the default ({@value
* org.xbill.DNS.SimpleResolver#DEFAULT_EDNS_PAYLOADSIZE}) is used.
* @param flags EDNS extended flags to be set in the OPT record.
* @param options EDNS options to be set in the OPT record, specified as a List of
* OPTRecord.Option elements.
* @throws IllegalArgumentException An invalid field was specified.
* @see OPTRecord
*/
void setEDNS(int version, int payloadSize, int flags, List<EDNSOption> options);
/**
* Sets the EDNS information on outgoing messages.
*
* @param version The EDNS version to use. 0 indicates EDNS0 and -1 indicates no EDNS.
* @param payloadSize The maximum DNS packet size that this host is capable of receiving over UDP.
* If 0 is specified, the default (1280) is used.
* @param flags EDNS extended flags to be set in the OPT record.
* @param options EDNS options to be set in the OPT record, specified as a List of
* OPTRecord.Option elements.
* @throws IllegalArgumentException An invalid field was specified.
* @see OPTRecord
*/
default void setEDNS(int version, int payloadSize, int flags, EDNSOption... options) {
setEDNS(
version,
payloadSize,
flags,
options == null ? Collections.emptyList() : Arrays.asList(options));
}
/**
* Specifies the TSIG key that messages will be signed with
*
* @param key The key
*/
void setTSIGKey(TSIG key);
/**
* Sets the amount of time to wait for a response before giving up.
*
* @param secs The number of seconds to wait.
* @param msecs The number of milliseconds to wait.
* @deprecated use {@link #setTimeout(Duration)}
*/
@Deprecated
default void setTimeout(int secs, int msecs) {
setTimeout(Duration.ofMillis(secs * 1000L + msecs));
}
/**
* Sets the amount of time to wait for a response before giving up.
*
* @param secs The number of seconds to wait.
* @deprecated use {@link #setTimeout(Duration)}
*/
@Deprecated
default void setTimeout(int secs) {
setTimeout(Duration.ofSeconds(secs));
}
/**
* Sets the amount of time to wait for a response before giving up.
*
* @param timeout The amount of time to wait.
*/
void setTimeout(Duration timeout);
/**
* Gets the amount of time to wait for a response before giving up.
*
* @see #setTimeout(Duration)
*/
default Duration getTimeout() {
return Duration.ofSeconds(10);
}
/**
* Sends a message and waits for a response.
*
* <p>The waiting is done on the calling thread. Do not call this method from async code, and
* especially not from tasks running on {@link ForkJoinPool#commonPool()}, use {@link
* #sendAsync(Message)} or {@link #sendAsync(Message, Executor)} instead.
*
* @param query The query to send.
* @return The response
* @throws IOException An error occurred while sending or receiving.
*/
default Message send(Message query) throws IOException {
try {
CompletableFuture<Message> result = sendAsync(query).toCompletableFuture();
return result.get(getTimeout().toMillis(), TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
} catch (ExecutionException e) {
if (e.getCause() instanceof IOException) {
throw (IOException) e.getCause();
} else {
throw new IOException(e.getCause());
}
} catch (TimeoutException e) {
throw new IOException(
"Timed out while trying to resolve "
+ query.getQuestion().getName()
+ "/"
+ Type.string(query.getQuestion().type)
+ ", id="
+ query.getHeader().getID(),
e);
}
}
/**
* Asynchronously sends a message using the default {@link ForkJoinPool#commonPool()}.
*
* <p>The default implementation calls the deprecated {@link #sendAsync(Message,
* ResolverListener)}. Implementors must override at least one of the {@code sendAsync} methods or
* a stack overflow will occur.
*
* @param query The query to send.
* @return A future that completes when the query is finished.
*/
default CompletionStage<Message> sendAsync(Message query) {
return sendAsync(query, ForkJoinPool.commonPool());
}
/**
* Asynchronously sends a message.
*
* <p>The default implementation calls the deprecated {@link #sendAsync(Message,
* ResolverListener)}. Implementors must override at least one of the {@code sendAsync} methods or
* a stack overflow will occur.
*
* @param query The query to send.
* @param executor The service to use for async operations.
* @return A future that completes when the query is finished.
*/
@SuppressWarnings("deprecation")
default CompletionStage<Message> sendAsync(Message query, Executor executor) {
CompletableFuture<Message> f = new CompletableFuture<>();
sendAsync(
query,
new ResolverListener() {
@Override
public void receiveMessage(Object id, Message m) {
f.complete(m);
}
@Override
public void handleException(Object id, Exception e) {
f.completeExceptionally(e);
}
});
return f;
}
/**
* Asynchronously sends a message registering a listener to receive a callback on success or
* exception. Multiple asynchronous lookups can be performed in parallel. The callback may be
* invoked from any thread.
*
* <p>The default implementation calls {@link #sendAsync(Message)}. Implementors must override at
* least one of the {@code sendAsync} methods or a stack overflow will occur.
*
* @param query The query to send
* @param listener The object containing the callbacks.
* @return An identifier, which is also a parameter in the callback
* @deprecated Use {@link #sendAsync(Message)}
*/
@Deprecated
default Object sendAsync(Message query, ResolverListener listener) {
final Object id = new Object();
CompletionStage<Message> f = sendAsync(query);
f.handleAsync(
(result, throwable) -> {
if (throwable != null) {
Exception exception;
if (throwable instanceof Exception) {
exception = (Exception) throwable;
} else {
exception = new Exception(throwable);
}
listener.handleException(id, exception);
return null;
}
listener.receiveMessage(id, result);
return null;
});
return id;
}
}