@Test public void udpTruncatedTcpFallbackTest() throws IOException { final int tcpResponseId = 42; class TestNetworkDataSource extends NetworkDataSource { boolean lastQueryUdp = false; @Override protected DnsMessage queryUdp(DnsMessage message, InetAddress address, int port) throws IOException { assertFalse(lastQueryUdp); lastQueryUdp = true; DnsMessage.Builder msg = DnsMessage.builder(); msg.setTruncated(true); return msg.build(); } @Override protected DnsMessage queryTcp(DnsMessage message, InetAddress address, int port) throws IOException { assertTrue(lastQueryUdp); lastQueryUdp = false; return DnsMessage.builder().setId(tcpResponseId).build(); } } TestNetworkDataSource world = new TestNetworkDataSource(); DnsQueryResult result = world.query(DnsMessage.builder().build(), null, 53); assertEquals(tcpResponseId, result.response.id); assertFalse(world.lastQueryUdp); }
@Override public StandardDnsQueryResult query(DnsMessage message, InetAddress address, int port) throws IOException { final QueryMode queryMode = getQueryMode(); boolean doUdpFirst; switch (queryMode) { case dontCare: case udpTcp: doUdpFirst = true; break; case tcp: doUdpFirst = false; break; default: throw new IllegalStateException("Unsupported query mode: " + queryMode); } List<IOException> ioExceptions = new ArrayList<>(2); DnsMessage dnsMessage = null; if (doUdpFirst) { try { dnsMessage = queryUdp(message, address, port); } catch (IOException e) { ioExceptions.add(e); } if (dnsMessage != null && !dnsMessage.truncated) { return new StandardDnsQueryResult(address, port, QueryMethod.udp, message, dnsMessage); } assert dnsMessage == null || dnsMessage.truncated || ioExceptions.size() == 1; LOGGER.log(Level.FINE, "Fallback to TCP because {0}", new Object[] { dnsMessage != null ? "response is truncated" : ioExceptions.get(0) }); } try { dnsMessage = queryTcp(message, address, port); } catch (IOException e) { ioExceptions.add(e); MultipleIoException.throwIfRequired(ioExceptions); } return new StandardDnsQueryResult(address, port, QueryMethod.tcp, message, dnsMessage); }
NetworkDataSource extends AbstractDnsDataSource { @Override public StandardDnsQueryResult query(DnsMessage message, InetAddress address, int port) throws IOException { final QueryMode queryMode = getQueryMode(); boolean doUdpFirst; switch (queryMode) { case dontCare: case udpTcp: doUdpFirst = true; break; case tcp: doUdpFirst = false; break; default: throw new IllegalStateException("Unsupported query mode: " + queryMode); } List<IOException> ioExceptions = new ArrayList<>(2); DnsMessage dnsMessage = null; if (doUdpFirst) { try { dnsMessage = queryUdp(message, address, port); } catch (IOException e) { ioExceptions.add(e); } if (dnsMessage != null && !dnsMessage.truncated) { return new StandardDnsQueryResult(address, port, QueryMethod.udp, message, dnsMessage); } assert dnsMessage == null || dnsMessage.truncated || ioExceptions.size() == 1; LOGGER.log(Level.FINE, "Fallback to TCP because {0}", new Object[] { dnsMessage != null ? "response is truncated" : ioExceptions.get(0) }); } try { dnsMessage = queryTcp(message, address, port); } catch (IOException e) { ioExceptions.add(e); MultipleIoException.throwIfRequired(ioExceptions); } return new StandardDnsQueryResult(address, port, QueryMethod.tcp, message, dnsMessage); } }
NetworkDataSource extends AbstractDnsDataSource { @Override public StandardDnsQueryResult query(DnsMessage message, InetAddress address, int port) throws IOException { final QueryMode queryMode = getQueryMode(); boolean doUdpFirst; switch (queryMode) { case dontCare: case udpTcp: doUdpFirst = true; break; case tcp: doUdpFirst = false; break; default: throw new IllegalStateException("Unsupported query mode: " + queryMode); } List<IOException> ioExceptions = new ArrayList<>(2); DnsMessage dnsMessage = null; if (doUdpFirst) { try { dnsMessage = queryUdp(message, address, port); } catch (IOException e) { ioExceptions.add(e); } if (dnsMessage != null && !dnsMessage.truncated) { return new StandardDnsQueryResult(address, port, QueryMethod.udp, message, dnsMessage); } assert dnsMessage == null || dnsMessage.truncated || ioExceptions.size() == 1; LOGGER.log(Level.FINE, "Fallback to TCP because {0}", new Object[] { dnsMessage != null ? "response is truncated" : ioExceptions.get(0) }); } try { dnsMessage = queryTcp(message, address, port); } catch (IOException e) { ioExceptions.add(e); MultipleIoException.throwIfRequired(ioExceptions); } return new StandardDnsQueryResult(address, port, QueryMethod.tcp, message, dnsMessage); }  }
NetworkDataSource extends AbstractDnsDataSource { @Override public StandardDnsQueryResult query(DnsMessage message, InetAddress address, int port) throws IOException { final QueryMode queryMode = getQueryMode(); boolean doUdpFirst; switch (queryMode) { case dontCare: case udpTcp: doUdpFirst = true; break; case tcp: doUdpFirst = false; break; default: throw new IllegalStateException("Unsupported query mode: " + queryMode); } List<IOException> ioExceptions = new ArrayList<>(2); DnsMessage dnsMessage = null; if (doUdpFirst) { try { dnsMessage = queryUdp(message, address, port); } catch (IOException e) { ioExceptions.add(e); } if (dnsMessage != null && !dnsMessage.truncated) { return new StandardDnsQueryResult(address, port, QueryMethod.udp, message, dnsMessage); } assert dnsMessage == null || dnsMessage.truncated || ioExceptions.size() == 1; LOGGER.log(Level.FINE, "Fallback to TCP because {0}", new Object[] { dnsMessage != null ? "response is truncated" : ioExceptions.get(0) }); } try { dnsMessage = queryTcp(message, address, port); } catch (IOException e) { ioExceptions.add(e); MultipleIoException.throwIfRequired(ioExceptions); } return new StandardDnsQueryResult(address, port, QueryMethod.tcp, message, dnsMessage); }  @Override StandardDnsQueryResult query(DnsMessage message, InetAddress address, int port); }
NetworkDataSource extends AbstractDnsDataSource { @Override public StandardDnsQueryResult query(DnsMessage message, InetAddress address, int port) throws IOException { final QueryMode queryMode = getQueryMode(); boolean doUdpFirst; switch (queryMode) { case dontCare: case udpTcp: doUdpFirst = true; break; case tcp: doUdpFirst = false; break; default: throw new IllegalStateException("Unsupported query mode: " + queryMode); } List<IOException> ioExceptions = new ArrayList<>(2); DnsMessage dnsMessage = null; if (doUdpFirst) { try { dnsMessage = queryUdp(message, address, port); } catch (IOException e) { ioExceptions.add(e); } if (dnsMessage != null && !dnsMessage.truncated) { return new StandardDnsQueryResult(address, port, QueryMethod.udp, message, dnsMessage); } assert dnsMessage == null || dnsMessage.truncated || ioExceptions.size() == 1; LOGGER.log(Level.FINE, "Fallback to TCP because {0}", new Object[] { dnsMessage != null ? "response is truncated" : ioExceptions.get(0) }); } try { dnsMessage = queryTcp(message, address, port); } catch (IOException e) { ioExceptions.add(e); MultipleIoException.throwIfRequired(ioExceptions); } return new StandardDnsQueryResult(address, port, QueryMethod.tcp, message, dnsMessage); }  @Override StandardDnsQueryResult query(DnsMessage message, InetAddress address, int port);  }