1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import jtreg.SkippedException; 25 26 import javax.naming.directory.InitialDirContext; 27 28 import java.io.IOException; 29 import java.net.BindException; 30 import java.net.InetAddress; 31 import java.net.ServerSocket; 32 33 import static java.util.concurrent.TimeUnit.NANOSECONDS; 34 import static jdk.test.lib.Utils.adjustTimeout; 35 36 /* 37 * @test 38 * @bug 8228580 39 * @summary Tests that we get a DNS response when the UDP DNS server returns a 40 * truncated response and the TCP DNS server does not respond at all 41 * after connect. 42 * @library ../lib/ 43 * @library /test/lib 44 * @modules java.base/sun.security.util 45 * @run main TcpTimeout 46 * @run main TcpTimeout -Dcom.sun.jndi.dns.timeout.initial=5000 47 */ 48 49 public class TcpTimeout extends DNSTestBase { 50 private TcpDnsServer tcpDnsServer; 51 52 /* The acceptable variation in timeout measurement. */ 53 private static final long TOLERANCE = adjustTimeout(5_000); 54 55 public static void main(String[] args) throws Exception { 56 new TcpTimeout().run(args); 57 } 58 59 @Override 60 public void runTest() throws Exception { 61 /* Default timeout value is 1 second, as stated in jdk.naming.dns 62 module docs. */ 63 long timeout = 1_000; 64 var envTimeout = env().get("com.sun.jndi.dns.timeout.initial"); 65 if (envTimeout != null) 66 timeout = Long.parseLong(String.valueOf(envTimeout)); 67 68 setContext(new InitialDirContext(env())); 69 70 long startNanos = System.nanoTime(); 71 72 /* perform query */ 73 var attrs = context().getAttributes("host1"); 74 75 long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos); 76 if (elapsed < timeout || elapsed > timeout + TOLERANCE) { 77 throw new RuntimeException("Query took " + elapsed + " ms. " 78 + ". Timeout value is " + timeout); 79 } 80 81 DNSTestUtils.debug(attrs); 82 83 /* Note that the returned attributes are truncated and the response 84 is not valid. */ 85 var txtAttr = attrs.get("TXT"); 86 if (txtAttr == null) 87 throw new RuntimeException("TXT attribute missing."); 88 } 89 90 @Override 91 public void initTest(String[] args) { 92 /* We need to bind the TCP server on the same port UDP server is 93 listening to. This maybe not be possible if the port is in use. Retry 94 several times relaying on UDP port randomness. */ 95 for (int i = 0; i < 5; i++) { 96 super.initTest(args); 97 var udpServer = (Server) env().get(DNSTestUtils.TEST_DNS_SERVER_THREAD); 98 int port = udpServer.getPort(); 99 try { 100 tcpDnsServer = new TcpDnsServer(port); 101 break; // success 102 } catch (BindException be) { 103 DNSTestUtils.debug("Failed to bind server socket on port " + port 104 + ", retry no. " + (i + 1)); 105 } catch (Exception ex) { 106 throw new RuntimeException("Unexpected exception during initTest", ex); 107 } finally { 108 if (tcpDnsServer == null) { // cleaup behind exceptions 109 super.cleanupTest(); 110 } 111 } 112 } 113 114 if (tcpDnsServer == null) { 115 throw new SkippedException("Cannot start TCP server after 5 tries, skip test"); 116 } 117 } 118 119 @Override 120 public void cleanupTest() { 121 super.cleanupTest(); 122 if (tcpDnsServer != null) 123 tcpDnsServer.stopServer(); 124 } 125 126 /** 127 * A TCP server that accepts a connection and does nothing else: causes read 128 * timeout on client side. 129 */ 130 private static class TcpDnsServer { 131 final ServerSocket serverSocket; 132 133 TcpDnsServer(int port) throws IOException { 134 serverSocket = new ServerSocket(port, 0, InetAddress.getLoopbackAddress()); 135 System.out.println("TcpDnsServer: listening on port " + port); 136 } 137 138 void stopServer() { 139 try { 140 if (serverSocket != null) 141 serverSocket.close(); 142 } 143 catch (Exception e) {} 144 } 145 } 146 }