Check the bindFuture before writing a DNS query

Related: #3149

Motivation:

DnsQueryContext, using the DatagramChannel bound in DnsNameResolver,
blindly writes to the channel without checking the bind future for
success.

Modifications:

Check the bindFuture before writing a DNS query to a DatagramChannel

Result:

Bug fixed
This commit is contained in:
Jay 2014-11-18 12:28:45 -08:00 committed by Trustin Lee
parent f4d3f81d6c
commit 2769ad428a
2 changed files with 30 additions and 10 deletions

View File

@ -87,6 +87,7 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
private static final DnsQueryEncoder ENCODER = new DnsQueryEncoder(); private static final DnsQueryEncoder ENCODER = new DnsQueryEncoder();
final Iterable<InetSocketAddress> nameServerAddresses; final Iterable<InetSocketAddress> nameServerAddresses;
final ChannelFuture bindFuture;
final DatagramChannel ch; final DatagramChannel ch;
/** /**
@ -248,12 +249,13 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
} }
this.nameServerAddresses = nameServerAddresses; this.nameServerAddresses = nameServerAddresses;
ch = newChannel(channelFactory, localAddress); bindFuture = newChannel(channelFactory, localAddress);
ch = (DatagramChannel) bindFuture.channel();
setMaxPayloadSize(4096); setMaxPayloadSize(4096);
} }
private DatagramChannel newChannel( private ChannelFuture newChannel(
ChannelFactory<? extends DatagramChannel> channelFactory, InetSocketAddress localAddress) { ChannelFactory<? extends DatagramChannel> channelFactory, InetSocketAddress localAddress) {
Bootstrap b = new Bootstrap(); Bootstrap b = new Bootstrap();
@ -266,15 +268,15 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
} }
}); });
DatagramChannel ch = (DatagramChannel) b.bind(localAddress).channel(); ChannelFuture bindFuture = b.bind(localAddress);
ch.closeFuture().addListener(new ChannelFutureListener() { bindFuture.channel().closeFuture().addListener(new ChannelFutureListener() {
@Override @Override
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) throws Exception {
clearCache(); clearCache();
} }
}); });
return ch; return bindFuture;
} }
/** /**

View File

@ -19,7 +19,6 @@ package io.netty.resolver.dns;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
import io.netty.channel.socket.DatagramChannel;
import io.netty.handler.codec.dns.DnsQuery; import io.netty.handler.codec.dns.DnsQuery;
import io.netty.handler.codec.dns.DnsQuestion; import io.netty.handler.codec.dns.DnsQuestion;
import io.netty.handler.codec.dns.DnsResource; import io.netty.handler.codec.dns.DnsResource;
@ -131,13 +130,32 @@ final class DnsQueryContext {
query.header().setRecursionDesired(recursionDesired); query.header().setRecursionDesired(recursionDesired);
query.addAdditionalResource(optResource); query.addAdditionalResource(optResource);
final DatagramChannel ch = parent.ch;
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{} WRITE: [{}: {}], {}", ch, id, nameServerAddr, question); logger.debug("{} WRITE: [{}: {}], {}", parent.ch, id, nameServerAddr, question);
} }
final ChannelFuture writeFuture = ch.writeAndFlush(query); sendQuery(query, nameServerAddr);
}
private void sendQuery(final DnsQuery query, final InetSocketAddress nameServerAddr) {
if (parent.bindFuture.isDone()) {
writeQuery(query, nameServerAddr);
} else {
parent.bindFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
writeQuery(query, nameServerAddr);
} else {
promise.tryFailure(future.cause());
}
}
});
}
}
private void writeQuery(final DnsQuery query, final InetSocketAddress nameServerAddr) {
final ChannelFuture writeFuture = parent.ch.writeAndFlush(query);
if (writeFuture.isDone()) { if (writeFuture.isDone()) {
onQueryWriteCompletion(writeFuture, nameServerAddr); onQueryWriteCompletion(writeFuture, nameServerAddr);
} else { } else {