7162687: enhance KDC server availability detection
authorweijun
Wed, 23 May 2012 15:51:10 +0800
changeset 12842 f6f9cb8f6b97
parent 12704 c516c24fa010
child 12843 f785258dea60
7162687: enhance KDC server availability detection Reviewed-by: valeriep
jdk/src/share/classes/sun/security/krb5/KdcComm.java
jdk/src/share/classes/sun/security/krb5/internal/NetClient.java
jdk/test/ProblemList.txt
jdk/test/sun/security/krb5/auto/BadKdc.java
jdk/test/sun/security/krb5/auto/MaxRetries.java
jdk/test/sun/security/krb5/auto/TcpTimeout.java
jdk/test/sun/security/krb5/auto/Unreachable.java
jdk/test/sun/security/krb5/auto/unreachable.krb5.conf
--- a/jdk/src/share/classes/sun/security/krb5/KdcComm.java	Mon May 21 19:28:41 2012 +0200
+++ b/jdk/src/share/classes/sun/security/krb5/KdcComm.java	Wed May 23 15:51:10 2012 +0800
@@ -365,37 +365,36 @@
 
             for (int i=1; i <= retries; i++) {
                 String proto = useTCP?"TCP":"UDP";
-                NetClient kdcClient = NetClient.getInstance(
-                        proto, kdc, port, timeout);
-                if (DEBUG) {
-                    System.out.println(">>> KDCCommunication: kdc=" + kdc
-                           + " " + proto + ":"
-                           +  port +  ", timeout="
-                           + timeout
-                           + ",Attempt =" + i
-                           + ", #bytes=" + obuf.length);
-                }
-                try {
-                    /*
-                     * Send the data to the kdc.
-                     */
-                    kdcClient.send(obuf);
-                    /*
-                     * And get a response.
-                     */
-                    ibuf = kdcClient.receive();
-                    break;
-                } catch (SocketTimeoutException se) {
+                try (NetClient kdcClient = NetClient.getInstance(
+                        proto, kdc, port, timeout)) {
                     if (DEBUG) {
-                        System.out.println ("SocketTimeOutException with " +
-                                            "attempt: " + i);
+                        System.out.println(">>> KDCCommunication: kdc=" + kdc
+                            + " " + proto + ":"
+                            +  port +  ", timeout="
+                            + timeout
+                            + ",Attempt =" + i
+                            + ", #bytes=" + obuf.length);
                     }
-                    if (i == retries) {
-                        ibuf = null;
-                        throw se;
+                    try {
+                        /*
+                        * Send the data to the kdc.
+                        */
+                        kdcClient.send(obuf);
+                        /*
+                        * And get a response.
+                        */
+                        ibuf = kdcClient.receive();
+                        break;
+                    } catch (SocketTimeoutException se) {
+                        if (DEBUG) {
+                            System.out.println ("SocketTimeOutException with " +
+                                                "attempt: " + i);
+                        }
+                        if (i == retries) {
+                            ibuf = null;
+                            throw se;
+                        }
                     }
-                } finally {
-                    kdcClient.close();
                 }
             }
             return ibuf;
--- a/jdk/src/share/classes/sun/security/krb5/internal/NetClient.java	Mon May 21 19:28:41 2012 +0200
+++ b/jdk/src/share/classes/sun/security/krb5/internal/NetClient.java	Wed May 23 15:51:10 2012 +0800
@@ -34,7 +34,7 @@
 import java.io.*;
 import java.net.*;
 
-public abstract class NetClient {
+public abstract class NetClient implements AutoCloseable {
     public static NetClient getInstance(String protocol, String hostname, int port,
             int timeout) throws IOException {
         if (protocol.equals("TCP")) {
@@ -45,9 +45,7 @@
     }
 
     abstract public void send(byte[] data) throws IOException;
-
     abstract public byte[] receive() throws IOException;
-
     abstract public void close() throws IOException;
 }
 
@@ -190,6 +188,7 @@
         iport = port;
         dgSocket = new DatagramSocket();
         dgSocket.setSoTimeout(timeout);
+        dgSocket.connect(iaddr, iport);
     }
 
     @Override
@@ -207,6 +206,9 @@
             dgSocket.receive(dgPacketIn);
         }
         catch (SocketException e) {
+            if (e instanceof PortUnreachableException) {
+                throw e;
+            }
             dgSocket.receive(dgPacketIn);
         }
         byte[] data = new byte[dgPacketIn.getLength()];
--- a/jdk/test/ProblemList.txt	Mon May 21 19:28:41 2012 +0200
+++ b/jdk/test/ProblemList.txt	Wed May 23 15:51:10 2012 +0800
@@ -222,6 +222,9 @@
 sun/net/www/protocol/http/B6299712.java                         macosx-all
 java/net/CookieHandler/CookieManagerTest.java                   macosx-all
 
+# 7164518
+sun/security/krb5/auto/Unreachable.java                         macosx-all
+
 # JPRT needs to set 127.0.0.1 in proxy bypass list
 java/net/URLClassLoader/closetest/CloseTest.java                macosx-all
 ############################################################################
--- a/jdk/test/sun/security/krb5/auto/BadKdc.java	Mon May 21 19:28:41 2012 +0200
+++ b/jdk/test/sun/security/krb5/auto/BadKdc.java	Wed May 23 15:51:10 2012 +0800
@@ -87,6 +87,10 @@
             throws Exception {
         System.setProperty("sun.security.krb5.debug", "true");
 
+        // Idle UDP sockets will trigger a SocketTimeoutException, without it,
+        // a PortUnreachableException will be thrown.
+        DatagramSocket d1 = null, d2 = null, d3 = null;
+
         // Make sure KDCs' ports starts with 1 and 2 and 3,
         // useful for checking debug output.
         int p1 = 10000 + new java.util.Random().nextInt(10000);
@@ -109,6 +113,8 @@
         Config.refresh();
 
         // Turn on k3 only
+        d1 = new DatagramSocket(p1);
+        d2 = new DatagramSocket(p2);
         KDC k3 = on(p3);
 
         test(expected[0]);
@@ -117,10 +123,17 @@
         test(expected[2]);
 
         k3.terminate(); // shutdown k3
+        d3 = new DatagramSocket(p3);
+
+        d2.close();
         on(p2);         // k2 is on
+
         test(expected[3]);
+        d1.close();
         on(p1);         // k1 and k2 is on
         test(expected[4]);
+
+        d3.close();
     }
 
     private static KDC on(int p) throws Exception {
--- a/jdk/test/sun/security/krb5/auto/MaxRetries.java	Mon May 21 19:28:41 2012 +0200
+++ b/jdk/test/sun/security/krb5/auto/MaxRetries.java	Wed May 23 15:51:10 2012 +0800
@@ -24,11 +24,13 @@
 /*
  * @test
  * @bug 6844193
+ * @compile -XDignore.symbol.file MaxRetries.java
  * @run main/othervm/timeout=300 MaxRetries
  * @summary support max_retries in krb5.conf
  */
 
 import java.io.*;
+import java.net.DatagramSocket;
 import java.security.Security;
 
 public class MaxRetries {
@@ -37,6 +39,10 @@
 
         System.setProperty("sun.security.krb5.debug", "true");
         new OneKDC(null).writeJAASConf();
+
+        // An idle UDP socket to revent PortUnreachableException
+        DatagramSocket ds = new DatagramSocket(33333);
+
         System.setProperty("java.security.krb5.conf", "alternative-krb5.conf");
 
         // For tryLast
@@ -78,6 +84,8 @@
 
         rewriteUdpPrefLimit(10000, 10); // realm rules
         test2("TCP");
+
+        ds.close();
     }
 
     /**
--- a/jdk/test/sun/security/krb5/auto/TcpTimeout.java	Mon May 21 19:28:41 2012 +0200
+++ b/jdk/test/sun/security/krb5/auto/TcpTimeout.java	Wed May 23 15:51:10 2012 +0800
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 6952519
+ * @compile -XDignore.symbol.file TcpTimeout.java
  * @run main/othervm TcpTimeout
  * @summary kdc_timeout is not being honoured when using TCP
  */
@@ -73,9 +74,7 @@
         // 5 sec on p1, 5 sec on p1, fail
         // 5 sec on p2, 5 sec on p2, fail
         // p3 ok, p3 ok again for preauth.
-        // The total time should be 20sec + 2x. x is processing time for AS-REQ.
         int count = 6;
-        long start = System.currentTimeMillis();
 
         ByteArrayOutputStream bo = new ByteArrayOutputStream();
         PrintStream oldout = System.out;
@@ -93,10 +92,5 @@
         if (count != 0) {
             throw new Exception("Retry count is " + count + " less");
         }
-
-        long end = System.currentTimeMillis();
-        if ((end - start)/1000L < 20) {
-            throw new Exception("Too fast? " + (end - start)/1000L);
-        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/Unreachable.java	Wed May 23 15:51:10 2012 +0800
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7162687
+ * @summary enhance KDC server availability detection
+ * @compile -XDignore.symbol.file Unreachable.java
+ * @run main/othervm/timeout=10 Unreachable
+ */
+
+import java.io.File;
+import javax.security.auth.login.LoginException;
+import sun.security.krb5.Config;
+
+public class Unreachable {
+
+    public static void main(String[] args) throws Exception {
+        File f = new File(
+                System.getProperty("test.src", "."), "unreachable.krb5.conf");
+        System.setProperty("java.security.krb5.conf", f.getPath());
+        Config.refresh();
+
+        // If PortUnreachableException is not received, the login will consume
+        // about 3*3*30 seconds and the test will timeout.
+        try {
+            Context.fromUserPass("name", "pass".toCharArray(), true);
+        } catch (LoginException le) {
+            // This is OK
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/unreachable.krb5.conf	Wed May 23 15:51:10 2012 +0800
@@ -0,0 +1,9 @@
+[libdefaults]
+   default_realm = RABBIT.HOLE
+[realms]
+
+RABBIT.HOLE = {
+   kdc = 127.0.0.1:13434
+   kdc = 127.0.0.1:13435
+   kdc = 127.0.0.1:13436
+}