Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, Address
obj.setRoundRobinInetAddress((Boolean)member.getValue());
}
break;
case "useTcpForFallbackDnsResolving":
if (member.getValue() instanceof Boolean) {
obj.setUseTcpForFallbackDnsResolving((Boolean)member.getValue());
}
break;
}
}
}
Expand Down Expand Up @@ -141,5 +146,6 @@ static void toJson(AddressResolverOptions obj, java.util.Map<String, Object> jso
json.put("ndots", obj.getNdots());
json.put("rotateServers", obj.isRotateServers());
json.put("roundRobinInetAddress", obj.isRoundRobinInetAddress());
json.put("useTcpForFallbackDnsResolving", obj.isUseTcpForFallbackDnsResolving());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ public class AddressResolverOptions {
*/
public static final boolean DEFAULT_ROUND_ROBIN_INET_ADDRESS = false;

/**
* The default whether to use TCP for DNS resolving if resolving via UDP times out = false
*/
public static final boolean DEFAULT_USE_TCP_FOR_FALLBACK_DNS_RESOLVING = false;

private String hostsPath;
private Buffer hostsValue;
private TimeUnit hostsRefreshPeriodUnit;
Expand All @@ -132,6 +137,7 @@ public class AddressResolverOptions {
private int ndots;
private boolean rotateServers;
private boolean roundRobinInetAddress;
private boolean useTcpForFallbackDnsResolving;

public AddressResolverOptions() {
servers = DEFAULT_SERVERS;
Expand All @@ -148,6 +154,7 @@ public AddressResolverOptions() {
roundRobinInetAddress = DEFAULT_ROUND_ROBIN_INET_ADDRESS;
hostsRefreshPeriodUnit = DEFAULT_HOSTS_REFRESH_PERIOD_UNIT;
hostsRefreshPeriod = DEFAULT_HOSTS_REFRESH_PERIOD;
useTcpForFallbackDnsResolving = DEFAULT_USE_TCP_FOR_FALLBACK_DNS_RESOLVING;
}

public AddressResolverOptions(AddressResolverOptions other) {
Expand All @@ -167,6 +174,7 @@ public AddressResolverOptions(AddressResolverOptions other) {
this.ndots = other.ndots;
this.rotateServers = other.rotateServers;
this.roundRobinInetAddress = other.roundRobinInetAddress;
this.useTcpForFallbackDnsResolving = other.useTcpForFallbackDnsResolving;
}

public AddressResolverOptions(JsonObject json) {
Expand Down Expand Up @@ -530,6 +538,24 @@ public AddressResolverOptions setRoundRobinInetAddress(boolean roundRobinInetAdd
return this;
}

/**
* @return the value {@code true} when using TCP for DNS resolving as a fallback is enabled when resolving via
* UDP times out.
*/
public boolean isUseTcpForFallbackDnsResolving() {
return useTcpForFallbackDnsResolving;
}

/**
* Set to {@code true} to enable using TCP as a fallback for DNS resolving when using UDP times out.
*
* @return a reference to this, so the API can be used fluently
*/
public AddressResolverOptions setUseTcpForFallbackDnsResolving(boolean useTcpForFallbackDnsResolving) {
this.useTcpForFallbackDnsResolving = useTcpForFallbackDnsResolving;
return this;
}

public JsonObject toJson() {
JsonObject json = new JsonObject();
AddressResolverOptionsConverter.toJson(this, json);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ private DnsAddressResolverProvider(VertxInternal vertx, AddressResolverOptions o
DnsNameResolverBuilder builder = new DnsNameResolverBuilder();
builder.hostsFileEntriesResolver(this);
builder.datagramChannelFactory(vertx.transport().datagramChannelFactory());
builder.socketChannelFactory(() -> (SocketChannel) vertx.transport().channelFactory(false).newChannel());
builder.socketChannelFactory(() -> (SocketChannel) vertx.transport().channelFactory(false).newChannel(),
options.isUseTcpForFallbackDnsResolving());
builder.nameServerProvider(nameServerAddressProvider);
builder.queryServerAddressStream(new ThreadLocalNameServerAddressStream(nameServerAddressProvider, ""));
builder.optResourceEnabled(options.isOptResourceEnabled());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class DnsTest extends VertxTestBase {

@Test
public void testDoNotLogActivity() throws Exception {
MockDnsServer mockDnsServer = new MockDnsServer(vertx);
MockDnsServer mockDnsServer = new MockDnsServer();
mockDnsServer.start();
try {
DnsClient client = vertx.createDnsClient(new DnsClientOptions(new DnsClientOptions().setLogActivity(false))
Expand Down
138 changes: 98 additions & 40 deletions vertx-core/src/test/java/io/vertx/test/fakedns/MockDnsServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@
package io.vertx.test.fakedns;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioIoHandler;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.dns.*;
import io.netty.handler.codec.dns.DnsRecord;
import io.netty.util.internal.PlatformDependent;
import io.vertx.core.Vertx;
import io.vertx.core.internal.VertxInternal;

import java.net.InetAddress;
import java.net.InetSocketAddress;
Expand All @@ -42,21 +43,15 @@ public class MockDnsServer {
private String ipAddress = IP_ADDRESS;
private int port = PORT;

private EventLoopGroup eventLoop;
private ChannelFactory<? extends Channel> channelFactory;
private Channel channel;
private final EventLoopGroup eventLoop = new MultiThreadIoEventLoopGroup(1, NioIoHandler.newFactory());
private final ChannelFactory<? extends Channel> channelFactory = NioDatagramChannel::new;
private Channel udpChannel;
private Channel tcpChannel;
private RecordStore store;
private List<Throwable> failures = new CopyOnWriteArrayList<>();
private final List<Throwable> failures = new CopyOnWriteArrayList<>();
private final Deque<DnsMessage> currentMessage = new ArrayDeque<>();

public MockDnsServer(Vertx vertx) {
this.eventLoop = ((VertxInternal) vertx).nettyEventLoopGroup().next();
this.channelFactory = ((VertxInternal) vertx).transport().datagramChannelFactory();
}

public MockDnsServer() {
this.eventLoop = null;
}
private boolean enableTcp = false;
private boolean enableUdp = true;

public MockDnsServer store(RecordStore store) {
this.store = store;
Expand All @@ -68,7 +63,12 @@ public RecordStore store() {
}

public InetSocketAddress localAddress() {
return (InetSocketAddress) channel.localAddress();
if (udpChannel != null) {
return (InetSocketAddress) udpChannel.localAddress();
} if (tcpChannel != null) {
return (InetSocketAddress) tcpChannel.localAddress();
}
throw new IllegalStateException("At least one of the channels must be started");
}

public MockDnsServer ipAddress(String ipAddress) {
Expand All @@ -81,28 +81,41 @@ public MockDnsServer port(int p) {
return this;
}

public MockDnsServer enableTcp(boolean enableTcp) {
this.enableTcp = enableTcp;
return this;
}

public MockDnsServer enableUdp(boolean enableUdp) {
this.enableUdp = enableUdp;
return this;
}

public void start() {
if (channel != null) {
if (udpChannel != null || tcpChannel != null) {
throw new IllegalStateException();
}
EventLoopGroup eventLoop = this.eventLoop;
ChannelFactory<? extends Channel> channelFactory = this.channelFactory;
if (eventLoop == null) {
eventLoop = new MultiThreadIoEventLoopGroup(1, NioIoHandler.newFactory());
channelFactory = NioDatagramChannel::new;
if (enableUdp) {
startUdp();
}
if (enableTcp) {
startTcp();
}
}

private void startUdp() {
Bootstrap bootstrap = new Bootstrap()
.group(eventLoop)
.channelFactory(channelFactory)
.handler(new ChannelInitializer<DatagramChannel>() {
@Override
protected void initChannel(DatagramChannel ch) throws Exception {
protected void initChannel(DatagramChannel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast(new DatagramDnsQueryDecoder())
.addLast(new DatagramDnsResponseEncoder())
.addLast(new SimpleChannelInboundHandler<DatagramDnsQuery>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsQuery msg) throws UnknownHostException {
protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsQuery msg) {
DnsRecord dnsRecord = msg.recordAt(DnsSection.QUESTION);
synchronized (MockDnsServer.this) {
currentMessage.add(msg);
Expand Down Expand Up @@ -140,33 +153,78 @@ protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsQuery msg) thr
PlatformDependent.throwException(e);
return;
} finally {
if (!started && this.eventLoop == null) {
if (!started) {
eventLoop.shutdownGracefully(0, 10, TimeUnit.SECONDS);
}
}
if (fut.isSuccess()) {
channel = fut.channel();
udpChannel = fut.channel();
} else {
if (this.eventLoop == null) {
eventLoop.shutdownGracefully(0, 10, TimeUnit.SECONDS);
}
PlatformDependent.throwException(fut.cause());
}
}

private void startTcp() {
ServerBootstrap tcpBootstrap = new ServerBootstrap()
.group(eventLoop)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast(new TcpDnsQueryDecoder())
.addLast(new TcpDnsResponseEncoder())
.addLast(new SimpleChannelInboundHandler<DnsQuery>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DnsQuery msg) {
DnsRecord dnsRecord = msg.recordAt(DnsSection.QUESTION);
synchronized (MockDnsServer.this) {
currentMessage.add(msg);
}

DefaultDnsResponse response = new DefaultDnsResponse(msg.id(), DnsOpCode.QUERY);
response.addRecord(DnsSection.QUESTION, dnsRecord);
RecordStore s = store;
if (s != null) {
Collection<DnsRecord> records;
try {
records = s.getRecords((DnsQuestion) dnsRecord);
} catch (Throwable failure) {
failures.add(failure);
return;
}
if (records != null) {
for (DnsRecord record : records) {
response.addRecord(DnsSection.ANSWER, record);
}
}
}
ctx.writeAndFlush(response);
}
});
}
});
try {
ChannelFuture tcpFut = tcpBootstrap.bind(ipAddress, port).sync();
tcpChannel = tcpFut.channel();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
PlatformDependent.throwException(e);
}
}

public List<Throwable> stop() throws Exception {
Channel channel = this.channel;
this.channel = null;
Channel tc = this.tcpChannel;
this.tcpChannel = null;
Channel channel = this.udpChannel;
this.udpChannel = null;

if (channel != null) {
try {
channel.close().sync();
} finally {
if (this.eventLoop == null) {
channel
.eventLoop()
.shutdownGracefully(0, 10, TimeUnit.SECONDS);
}
}
channel.eventLoop().parent().shutdownGracefully(0, 10, TimeUnit.SECONDS);
channel.close().sync();
} else if (tc != null) {
tc.eventLoop().parent().shutdownGracefully(0, 10, TimeUnit.SECONDS);
Comment thread
vietj marked this conversation as resolved.
tc.close().sync();
}
return failures;
}
Expand Down
2 changes: 1 addition & 1 deletion vertx-core/src/test/java/io/vertx/tests/dns/DNSTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public DNSTest() {
@Override
public void setUp() throws Exception {
super.setUp();
mockDnsServer = new MockDnsServer(vertx);
mockDnsServer = new MockDnsServer();
mockDnsServer.start();
}

Expand Down
Loading