8000 DnsNameResolver: Fail query if id space is exhausted (#13784) · netty/netty@0e7c27c · GitHub
[go: up one dir, main page]

Skip to content

Commit 0e7c27c

Browse files
authored
DnsNameResolver: Fail query if id space is exhausted (#13784)
Motivation: When we try to execute a query we will try to select / generate an id that is used. When we are not able to find one we throw an IllegalStateException. In this case we also need to ensure we fail the original promise as otherwise the user might never be notified of the problem. Modifications: - Move throw code out of the DnsQueryContextManager to make it easier to reason about - Fail query with IllegalStateException Result: Query will be correctly failed in the case of id space exhausting
1 parent b194741 commit 0e7c27c

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

resolver-dns/src/main/java/io/netty/resolver/dns/DnsQueryContext.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ abstract class DnsQueryContext {
8181

8282
private volatile Future<?> timeoutFuture;
8383

84-
private int id = -1;
84+
private int id = Integer.MIN_VALUE;
8585

8686
DnsQueryContext(Channel channel,
8787
Future<? extends Channel> channelReadyFuture,
@@ -172,8 +172,15 @@ final DnsQuestion question() {
172172
* @return the {@link ChannelFuture} that is notified once once the write completes.
173173
*/
174174
final ChannelFuture writeQuery(boolean flush) {
175-
assert id == -1 : this.getClass().getSimpleName() + ".writeQuery(...) can only be executed once.";
176-
id = queryContextManager.add(nameServerAddr, this);
175+
assert id == Integer.MIN_VALUE : this.getClass().getSimpleName() +
176+
".writeQuery(...) can only be executed once.";
177+
178+
if ((id = queryContextManager.add(nameServerAddr, this)) == -1) {
179+
// We did exhaust the id space, fail the query
180+
IllegalStateException e = new IllegalStateException("query ID space exhausted: " + question());
181+
finishFailure("failed to send a query via " + protocol(), e, false);
182+
return channel.newFailedFuture(e);
183+
}
177184

178185
// Ensure we remove the id from the QueryContextManager once the query completes.
179186
promise.addListener(new FutureListener<AddressedEnvelope<DnsResponse, InetSocketAddress>>() {

resolver-dns/src/main/java/io/netty/resolver/dns/DnsQueryContextManager.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,27 @@ final class DnsQueryContextManager {
3838
private final Map<InetSocketAddress, DnsQueryContextMap> map =
3939
new HashMap<InetSocketAddress, DnsQueryContextMap>();
4040

41+
/**
42+
* Add {@link DnsQueryContext} to the context manager and return the ID that should be used for the query.
43+
* This method will return {@code -1} if an ID could not be generated and the context was not stored.
44+
*
45+
* @param nameServerAddr The {@link InetSocketAddress} of the nameserver to query.
46+
* @param qCtx The {@link {@link DnsQueryContext} to store.
47+
* @return the ID that should be used or {@code -1} if none could be generated.
48+
*/
4149
int add(InetSocketAddress nameServerAddr, DnsQueryContext qCtx) {
4250
final DnsQueryContextMap contexts = getOrCreateContextMap(nameServerAddr);
4351
return contexts.add(qCtx);
4452
}
4553

54+
/**
55+
* Return the {@link DnsQueryContext} for the given {@link InetSocketAddress} and id or {@code null} if
56+
* none could be found.
57+
*
58+
* @param nameServerAddr The {@link InetSocketAddress} of the nameserver.
59+
* @param id The id that identifies the {@link DnsQueryContext} and was used for the query.
60+
* @return The context or {@code null} if none could be found.
61+
*/
4662
DnsQueryContext get(InetSocketAddress nameServerAddr, int id) {
4763
final DnsQueryContextMap contexts = getContextMap(nameServerAddr);
4864
if (contexts == null) {
@@ -51,6 +67,14 @@ DnsQueryContext get(InetSocketAddress nameServerAddr, int id) {
5167
return contexts.get(id);
5268
}
5369

70+
/**
71+
* Remove the {@link DnsQueryContext} for the given {@link InetSocketAddress} and id or {@code null} if
72+
* none could be found.
73+
*
74+
* @param nameServerAddr The {@link InetSocketAddress} of the nameserver.
75+
* @param id The id that identifies the {@link DnsQueryContext} and was used for the query.
76+
* @return The context or {@code null} if none could be removed.
77+
*/
5478
DnsQueryContext remove(InetSocketAddress nameServerAddr, int id) {
5579
final DnsQueryContextMap contexts = getContextMap(nameServerAddr);
5680
if (contexts == null) {
@@ -150,8 +174,7 @@ synchronized int add(DnsQueryContext ctx) {
150174

151175
id = id + 1 & 0xFFFF;
152176
if (++tries >= MAX_TRIES) {
153-
throw new IllegalStateException(
154-
"query ID space exhausted after " + MAX_TRIES + ": " + ctx.question());
177+
return -1;
155178
}
156179
}
157180
}

0 commit comments

Comments
 (0)
0