Merge
authormullan
Fri, 15 Jun 2012 08:47:41 -0400
changeset 13022 a7af6f12248a
parent 13021 72a4386f8976 (current diff)
parent 13019 7bde6e4fff5c (diff)
child 13023 2bb2271eadf6
Merge
--- a/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java	Fri Jun 15 08:43:31 2012 -0400
+++ b/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java	Fri Jun 15 08:47:41 2012 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -812,101 +812,119 @@
         }
     }
 
-    /**
-         * Inserts a row that has been inserted into the given
-         * <code>CachedRowSet</code> object into the data source from which
-         * the rowset is derived, returning <code>false</code> if the insertion
-         * was successful.
-         *
-         * @param crs the <code>CachedRowSet</code> object that has had a row inserted
-         *            and to whose underlying data source the row will be inserted
-         * @param pstmt the <code>PreparedStatement</code> object that will be used
-         *              to execute the insertion
-         * @return <code>false</code> to indicate that the insertion was successful;
-         *         <code>true</code> otherwise
-         * @throws SQLException if a database access error occurs
-         */
-    private boolean insertNewRow(CachedRowSet crs,
-        PreparedStatement pstmt, CachedRowSetImpl crsRes) throws SQLException {
-        int i = 0;
-        int icolCount = crs.getMetaData().getColumnCount();
+   /**
+    * Inserts a row that has been inserted into the given
+    * <code>CachedRowSet</code> object into the data source from which
+    * the rowset is derived, returning <code>false</code> if the insertion
+    * was successful.
+    *
+    * @param crs the <code>CachedRowSet</code> object that has had a row inserted
+    *            and to whose underlying data source the row will be inserted
+    * @param pstmt the <code>PreparedStatement</code> object that will be used
+    *              to execute the insertion
+    * @return <code>false</code> to indicate that the insertion was successful;
+    *         <code>true</code> otherwise
+    * @throws SQLException if a database access error occurs
+    */
+   private boolean insertNewRow(CachedRowSet crs,
+       PreparedStatement pstmt, CachedRowSetImpl crsRes) throws SQLException {
+
+       boolean returnVal = false;
 
-        boolean returnVal = false;
-        PreparedStatement pstmtSel = con.prepareStatement(selectCmd,
-                        ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
-        ResultSet rs, rs2 = null;
-        DatabaseMetaData dbmd = con.getMetaData();
-        rs = pstmtSel.executeQuery();
-        String table = crs.getTableName();
-        rs2 = dbmd.getPrimaryKeys(null, null, table);
-        String [] primaryKeys = new String[icolCount];
-        int k = 0;
-        while(rs2.next()) {
-            String pkcolname = rs2.getString("COLUMN_NAME");
-            primaryKeys[k] = pkcolname;
-            k++;
-        }
+       try (PreparedStatement pstmtSel = con.prepareStatement(selectCmd,
+                       ResultSet.TYPE_SCROLL_SENSITIVE,
+                       ResultSet.CONCUR_READ_ONLY);
+            ResultSet rs = pstmtSel.executeQuery();
+            ResultSet rs2 = con.getMetaData().getPrimaryKeys(null, null,
+                       crs.getTableName())
+       ) {
+
+           ResultSetMetaData rsmd = crs.getMetaData();
+           int icolCount = rsmd.getColumnCount();
+           String[] primaryKeys = new String[icolCount];
+           int k = 0;
+           while (rs2.next()) {
+               primaryKeys[k] = rs2.getString("COLUMN_NAME");
+               k++;
+           }
+
+           if (rs.next()) {
+               for (String pkName : primaryKeys) {
+                   if (!isPKNameValid(pkName, rsmd)) {
+
+                       /* We came here as one of the the primary keys
+                        * of the table is not present in the cached
+                        * rowset object, it should be an autoincrement column
+                        * and not included while creating CachedRowSet
+                        * Object, proceed to check for other primary keys
+                        */
+                       continue;
+                   }
 
-        if(rs.next()) {
-            for(int j=0;j<primaryKeys.length;j++) {
-                if(primaryKeys[j] != null) {
-                    if(crs.getObject(primaryKeys[j]) == null){
-                        break;
-                    }
-                    String crsPK = (crs.getObject(primaryKeys[j])).toString();
-                    String rsPK = (rs.getObject(primaryKeys[j])).toString();
-                    if(crsPK.equals(rsPK)) {
-                        returnVal = true;
-                        this.crsResolve.moveToInsertRow();
-                        for(i = 1; i <= icolCount; i++) {
-                            String colname = (rs.getMetaData()).getColumnName(i);
-                            if(colname.equals(primaryKeys[j]))
-                                this.crsResolve.updateObject(i,rsPK);
-                            else
-                                this.crsResolve.updateNull(i);
-                        }
-                        this.crsResolve.insertRow();
-                        this.crsResolve.moveToCurrentRow();
-                    }
-                }
-            }
-        }
-        if(returnVal)
-            return returnVal;
+                   Object crsPK = crs.getObject(pkName);
+                   if (crsPK == null) {
+                       /*
+                        * It is possible that the PK is null on some databases
+                        * and will be filled in at insert time (MySQL for example)
+                        */
+                       break;
+                   }
+
+                   String rsPK = rs.getObject(pkName).toString();
+                   if (crsPK.toString().equals(rsPK)) {
+                       returnVal = true;
+                       this.crsResolve.moveToInsertRow();
+                       for (int i = 1; i <= icolCount; i++) {
+                           String colname = (rs.getMetaData()).getColumnName(i);
+                           if (colname.equals(pkName))
+                               this.crsResolve.updateObject(i,rsPK);
+                           else
+                               this.crsResolve.updateNull(i);
+                       }
+                       this.crsResolve.insertRow();
+                       this.crsResolve.moveToCurrentRow();
+                   }
+               }
+           }
+
+           if (returnVal) {
+               return returnVal;
+           }
 
-        try {
-            for (i = 1; i <= icolCount; i++) {
-                Object obj = crs.getObject(i);
-                if (obj != null) {
-                    pstmt.setObject(i, obj);
-                } else {
-                    pstmt.setNull(i,crs.getMetaData().getColumnType(i));
-                }
-            }
+           try {
+               for (int i = 1; i <= icolCount; i++) {
+                   Object obj = crs.getObject(i);
+                   if (obj != null) {
+                       pstmt.setObject(i, obj);
+                   } else {
+                       pstmt.setNull(i,crs.getMetaData().getColumnType(i));
+                   }
+               }
 
-             i = pstmt.executeUpdate();
-             return false;
+               pstmt.executeUpdate();
+               return false;
 
-        } catch (SQLException ex) {
-            /**
-             * Cursor will come here if executeUpdate fails.
-             * There can be many reasons why the insertion failed,
-             * one can be violation of primary key.
-             * Hence we cannot exactly identify why the insertion failed
-             * Present the current row as a null row to the user.
-             **/
-            this.crsResolve.moveToInsertRow();
+           } catch (SQLException ex) {
+               /*
+                * Cursor will come here if executeUpdate fails.
+                * There can be many reasons why the insertion failed,
+                * one can be violation of primary key.
+                * Hence we cannot exactly identify why the insertion failed,
+                * present the current row as a null row to the caller.
+                */
+               this.crsResolve.moveToInsertRow();
 
-            for(i = 1; i <= icolCount; i++) {
-               this.crsResolve.updateNull(i);
-            }
+               for (int i = 1; i <= icolCount; i++) {
+                   this.crsResolve.updateNull(i);
+               }
 
-            this.crsResolve.insertRow();
-            this.crsResolve.moveToCurrentRow();
+               this.crsResolve.insertRow();
+               this.crsResolve.moveToCurrentRow();
 
-            return true;
-        }
-    }
+               return true;
+           }
+       }
+   }
 
 /**
  * Deletes the row in the underlying data source that corresponds to
@@ -1437,4 +1455,25 @@
     }
 
     static final long serialVersionUID =-8506030970299413976L;
+
+    /**
+     * Validate whether the Primary Key is known to the CachedRowSet.  If it is
+     * not, it is an auto-generated key
+     * @param pk - Primary Key to validate
+     * @param rsmd - ResultSetMetadata for the RowSet
+     * @return true if found, false otherwise (auto generated key)
+     */
+    private boolean isPKNameValid(String pk, ResultSetMetaData rsmd) throws SQLException {
+        boolean isValid = false;
+        int cols = rsmd.getColumnCount();
+        for(int i = 1; i<= cols; i++) {
+            String colName = rsmd.getColumnClassName(i);
+            if(colName.equalsIgnoreCase(pk)) {
+                isValid = true;
+                break;
+            }
+        }
+
+        return isValid;
+    }
 }
--- a/jdk/src/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java	Fri Jun 15 08:43:31 2012 -0400
+++ b/jdk/src/share/classes/com/sun/rowset/internal/XmlReaderContentHandler.java	Fri Jun 15 08:47:41 2012 -0400
@@ -764,6 +764,7 @@
                     rs.next();
                     rs.setOriginalRow();
                     applyUpdates();
+                    rs.deleteRow();
                 } catch (SQLException ex) {
                     throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errdel").toString() , ex.getMessage()));
                 }
--- a/jdk/src/share/classes/java/util/HashMap.java	Fri Jun 15 08:43:31 2012 -0400
+++ b/jdk/src/share/classes/java/util/HashMap.java	Fri Jun 15 08:47:41 2012 -0400
@@ -288,12 +288,11 @@
      * in lower bits.
      */
     final int hash(Object k) {
-        int h = hashSeed;
         if (k instanceof String) {
-            return ((String)k).hash32();
+            return ((String) k).hash32();
         }
 
-        h ^= k.hashCode();
+        int  h = hashSeed ^ k.hashCode();
 
         // This function ensures that hashCodes that differ only by
         // constant multiples at each bit position have a bounded
--- a/jdk/src/share/classes/java/util/Hashtable.java	Fri Jun 15 08:43:31 2012 -0400
+++ b/jdk/src/share/classes/java/util/Hashtable.java	Fri Jun 15 08:47:41 2012 -0400
@@ -194,19 +194,17 @@
     transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);
 
     private int hash(Object k) {
-        int h = hashSeed;
-
         if (k instanceof String) {
             return ((String)k).hash32();
-        } else {
-            h ^= k.hashCode();
+        }
+
+        int h = hashSeed ^ k.hashCode();
 
-            // This function ensures that hashCodes that differ only by
-            // constant multiples at each bit position have a bounded
-            // number of collisions (approximately 8 at default load factor).
-            h ^= (h >>> 20) ^ (h >>> 12);
-            return h ^ (h >>> 7) ^ (h >>> 4);
-        }
+        // This function ensures that hashCodes that differ only by
+        // constant multiples at each bit position have a bounded
+        // number of collisions (approximately 8 at default load factor).
+        h ^= (h >>> 20) ^ (h >>> 12);
+        return h ^ (h >>> 7) ^ (h >>> 4);
     }
 
     /**
@@ -1015,7 +1013,7 @@
      */
     private static class Entry<K,V> implements Map.Entry<K,V> {
         final int hash;
-        K key;
+        final K key;
         V value;
         Entry<K,V> next;
 
--- a/jdk/src/share/classes/java/util/WeakHashMap.java	Fri Jun 15 08:43:31 2012 -0400
+++ b/jdk/src/share/classes/java/util/WeakHashMap.java	Fri Jun 15 08:47:41 2012 -0400
@@ -295,13 +295,11 @@
      * otherwise encounter collisions for hashCodes that do not differ
      * in lower bits.
      */
-    int hash(Object k) {
-        int h = hashSeed;
+    final int hash(Object k) {
         if (k instanceof String) {
             return ((String) k).hash32();
-        } else {
-            h ^= k.hashCode();
         }
+        int  h = hashSeed ^ k.hashCode();
 
         // This function ensures that hashCodes that differ only by
         // constant multiples at each bit position have a bounded
--- a/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java	Fri Jun 15 08:43:31 2012 -0400
+++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java	Fri Jun 15 08:47:41 2012 -0400
@@ -269,13 +269,11 @@
      * differ in lower or upper bits.
      */
     private int hash(Object k) {
-       int h = hashSeed;
-
         if (k instanceof String) {
             return ((String) k).hash32();
         }
 
-        h ^= k.hashCode();
+        int h = hashSeed ^ k.hashCode();
 
         // Spread bits to regularize both segment and index locations,
         // using variant of single-word Wang/Jenkins hash.
--- a/jdk/src/share/demo/jvmti/hprof/hprof_table.c	Fri Jun 15 08:43:31 2012 -0400
+++ b/jdk/src/share/demo/jvmti/hprof/hprof_table.c	Fri Jun 15 08:47:41 2012 -0400
@@ -120,7 +120,7 @@
     TableIndex     table_incr;          /* Suggested increment size. */
     TableIndex     hash_bucket_count;   /* Number of hash buckets. */
     int            elem_size;           /* Size of element. */
-    int            info_size;           /* Size of info structure. */
+    int            info_size;           /* Size of info structure (can be 0). */
     void          *freed_bv;            /* Freed element bit vector */
     int            freed_count;         /* Count of freed'd elements */
     TableIndex     freed_start;         /* First freed in table */
@@ -208,9 +208,6 @@
 {
     TableElement *element;
 
-    if ( ltable->info_size == 0 ) {
-        return NULL;
-    }
     element = (TableElement*)ELEMENT_PTR(ltable,index);
     return element->info;
 }
@@ -760,7 +757,11 @@
                 void *info;
 
                 get_key(ltable, index, &key_ptr, &key_len);
-                info = get_info(ltable, index);
+                if ( ltable->info_size == 0 ) {
+                    info = NULL;
+                } else {
+                    info = get_info(ltable, index);
+                }
                 (*func)(SANITY_ADD_HARE(index, ltable->hare), key_ptr, key_len, info, arg);
                 if ( is_freed_entry(ltable, index) ) {
                     fcount++;
--- a/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c	Fri Jun 15 08:43:31 2012 -0400
+++ b/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c	Fri Jun 15 08:47:41 2012 -0400
@@ -119,9 +119,13 @@
 
     /* create a socket */
     fd = socket(AF_INET, SOCK_STREAM, 0);
+    if ( fd < 0 ) {
+        return -1;
+    }
 
     /* find remote host's addr from name */
     if ((hentry = gethostbyname(hostname)) == NULL) {
+        (void)close(fd);
         return -1;
     }
     (void)memset((char *)&s, 0, sizeof(s));
@@ -134,6 +138,7 @@
 
     /* now try connecting */
     if (-1 == connect(fd, (struct sockaddr*)&s, sizeof(s))) {
+        (void)close(fd);
         return 0;
     }
     return fd;
--- a/jdk/src/windows/native/sun/nio/ch/SocketDispatcher.c	Fri Jun 15 08:43:31 2012 -0400
+++ b/jdk/src/windows/native/sun/nio/ch/SocketDispatcher.c	Fri Jun 15 08:47:41 2012 -0400
@@ -141,41 +141,54 @@
 
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_SocketDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo,
-                                       jlong address, jint len)
+                                       jlong address, jint total)
 {
     /* set up */
     int i = 0;
     DWORD written = 0;
+    jint count = 0;
     jint fd = fdval(env, fdo);
     WSABUF buf;
 
-    /* limit size */
-    if (len > MAX_BUFFER_SIZE)
-        len = MAX_BUFFER_SIZE;
+    do {
+        /* limit size */
+        jint len = total - count;
+        if (len > MAX_BUFFER_SIZE)
+            len = MAX_BUFFER_SIZE;
 
-    /* copy iovec into WSABUF */
-    buf.buf = (char *)address;
-    buf.len = (u_long)len;
+        /* copy iovec into WSABUF */
+        buf.buf = (char *)address;
+        buf.len = (u_long)len;
+
+        /* write from the buffer */
+        i = WSASend((SOCKET)fd,     /* Socket */
+                    &buf,           /* pointers to the buffers */
+                    (DWORD)1,       /* number of buffers to process */
+                    &written,       /* receives number of bytes written */
+                    0,              /* no flags */
+                    0,              /* no overlapped sockets */
+                    0);             /* no completion routine */
 
-    /* read into the buffers */
-    i = WSASend((SOCKET)fd, /* Socket */
-            &buf,           /* pointers to the buffers */
-            (DWORD)1,       /* number of buffers to process */
-            &written,       /* receives number of bytes written */
-            0,              /* no flags */
-            0,              /* no overlapped sockets */
-            0);             /* no completion routine */
+        if (i == SOCKET_ERROR) {
+            if (count > 0) {
+                /* can't throw exception when some bytes have been written */
+                break;
+            } else {
+               int theErr = (jint)WSAGetLastError();
+               if (theErr == WSAEWOULDBLOCK) {
+                   return IOS_UNAVAILABLE;
+               }
+               JNU_ThrowIOExceptionWithLastError(env, "Write failed");
+               return IOS_THROWN;
+            }
+        }
 
-    if (i == SOCKET_ERROR) {
-        int theErr = (jint)WSAGetLastError();
-        if (theErr == WSAEWOULDBLOCK) {
-            return IOS_UNAVAILABLE;
-        }
-        JNU_ThrowIOExceptionWithLastError(env, "Write failed");
-        return IOS_THROWN;
-    }
+        count += written;
+        address += written;
 
-    return convertReturnVal(env, (jint)written, JNI_FALSE);
+    } while ((count < total) && (written == MAX_BUFFER_SIZE));
+
+    return count;
 }
 
 JNIEXPORT jlong JNICALL
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/SocketChannel/ShortWrite.java	Fri Jun 15 08:47:41 2012 -0400
@@ -0,0 +1,136 @@
+/*
+ * 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 7176630
+ * @summary Check for short writes on SocketChannels configured in blocking mode
+ */
+
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import java.util.Random;
+import java.util.zip.CRC32;
+
+public class ShortWrite {
+
+    static final Random rand = new Random();
+
+    /**
+     * Returns a checksum on the remaining bytes in the given buffer.
+     */
+    static long computeChecksum(ByteBuffer bb) {
+        CRC32 crc32 = new CRC32();
+        crc32.update(bb);
+        return crc32.getValue();
+    }
+
+    /**
+     * A task that reads the expected number of bytes and returns the CRC32
+     * of those bytes.
+     */
+    static class Reader implements Callable<Long> {
+        final SocketChannel sc;
+        final ByteBuffer buf;
+
+        Reader(SocketChannel sc, int expectedSize) {
+            this.sc = sc;
+            this.buf = ByteBuffer.allocate(expectedSize);
+        }
+
+        public Long call() throws Exception {
+            while (buf.hasRemaining()) {
+                int n = sc.read(buf);
+                if (n == -1)
+                    throw new RuntimeException("Premature EOF encountered");
+            }
+            buf.flip();
+            return computeChecksum(buf);
+        }
+    }
+
+    /**
+     * Run test with a write of the given number of bytes.
+     */
+    static void test(ExecutorService pool,
+                     SocketChannel source,
+                     SocketChannel sink,
+                     int size)
+        throws Exception
+    {
+        System.out.println(size);
+
+        // random bytes in the buffer
+        ByteBuffer buf = ByteBuffer.allocate(size);
+        rand.nextBytes(buf.array());
+
+        // submit task to read the bytes
+        Future<Long> result = pool.submit(new Reader(sink, size));
+
+        // write the bytes
+        int n = source.write(buf);
+        if (n != size)
+            throw new RuntimeException("Short write detected");
+
+        // check the bytes that were received match
+        buf.rewind();
+        long expected = computeChecksum(buf);
+        long actual = result.get();
+        if (actual != expected)
+            throw new RuntimeException("Checksum did not match");
+    }
+
+
+    public static void main(String[] args) throws Exception {
+        ExecutorService pool = Executors.newSingleThreadExecutor();
+        try {
+            try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
+                ssc.bind(new InetSocketAddress(0));
+                InetAddress lh = InetAddress.getLocalHost();
+                int port = ssc.socket().getLocalPort();
+                SocketAddress sa = new InetSocketAddress(lh, port);
+
+                try (SocketChannel source = SocketChannel.open(sa);
+                     SocketChannel sink = ssc.accept())
+                {
+                    // run tests on sizes around 128k as that is the problem
+                    // area on Windows.
+                    int BOUNDARY = 128 * 1024;
+                    for (int size=(BOUNDARY-2); size<=(BOUNDARY+2); size++) {
+                        test(pool, source, sink, size);
+                    }
+
+                    // run tests on random sizes
+                    for (int i=0; i<20; i++) {
+                        int size = rand.nextInt(1024*1024);
+                        test(pool, source, sink, size);
+                    }
+                }
+            }
+
+        } finally {
+            pool.shutdown();
+        }
+    }
+}
--- a/jdk/test/sun/security/krb5/auto/TcpTimeout.java	Fri Jun 15 08:43:31 2012 -0400
+++ b/jdk/test/sun/security/krb5/auto/TcpTimeout.java	Fri Jun 15 08:47:41 2012 -0400
@@ -48,49 +48,60 @@
         k.addPrincipalRandKey("krbtgt/" + OneKDC.REALM);
 
         // Start two listener that does not communicate, simulate timeout
-        int p1 = new ServerSocket(0).getLocalPort();
-        int p2 = new ServerSocket(0).getLocalPort();
+        ServerSocket ss1 = null;
+        ServerSocket ss2 = null;
 
-        FileWriter fw = new FileWriter("alternative-krb5.conf");
+        try {
+            ss1 = new ServerSocket(0);
+            ss2 = new ServerSocket(0);
+            int p1 = ss1.getLocalPort();
+            int p2 = ss2.getLocalPort();
+
+            FileWriter fw = new FileWriter("alternative-krb5.conf");
 
-        fw.write("[libdefaults]\n" +
-                "udp_preference_limit = 1\n" +
-                "max_retries = 2\n" +
-                "default_realm = " + OneKDC.REALM + "\n" +
-                "kdc_timeout = 5000\n");
-        fw.write("[realms]\n" + OneKDC.REALM + " = {\n" +
-                "kdc = " + OneKDC.KDCHOST + ":" + p1 + "\n" +
-                "kdc = " + OneKDC.KDCHOST + ":" + p2 + "\n" +
-                "kdc = " + OneKDC.KDCHOST + ":" + p3 + "\n" +
-                "}\n");
+            fw.write("[libdefaults]\n" +
+                    "udp_preference_limit = 1\n" +
+                    "max_retries = 2\n" +
+                    "default_realm = " + OneKDC.REALM + "\n" +
+                    "kdc_timeout = 5000\n");
+            fw.write("[realms]\n" + OneKDC.REALM + " = {\n" +
+                    "kdc = " + OneKDC.KDCHOST + ":" + p1 + "\n" +
+                    "kdc = " + OneKDC.KDCHOST + ":" + p2 + "\n" +
+                    "kdc = " + OneKDC.KDCHOST + ":" + p3 + "\n" +
+                    "}\n");
 
-        fw.close();
-        System.setProperty("java.security.krb5.conf", "alternative-krb5.conf");
-        Config.refresh();
-
-        System.out.println("Ports opened on " + p1 + ", " + p2 + ", " + p3);
+            fw.close();
+            System.setProperty("java.security.krb5.conf",
+                    "alternative-krb5.conf");
+            Config.refresh();
 
-        // The correct behavior should be:
-        // 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.
-        int count = 6;
+            System.out.println("Ports opened on " + p1 + ", " + p2 + ", " + p3);
+
+            // The correct behavior should be:
+            // 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.
+            int count = 6;
+
+            ByteArrayOutputStream bo = new ByteArrayOutputStream();
+            PrintStream oldout = System.out;
+            System.setOut(new PrintStream(bo));
+            Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false);
+            System.setOut(oldout);
 
-        ByteArrayOutputStream bo = new ByteArrayOutputStream();
-        PrintStream oldout = System.out;
-        System.setOut(new PrintStream(bo));
-        Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false);
-        System.setOut(oldout);
-
-        String[] lines = new String(bo.toByteArray()).split("\n");
-        for (String line: lines) {
-            if (line.startsWith(">>> KDCCommunication")) {
-                System.out.println(line);
-                count--;
+            String[] lines = new String(bo.toByteArray()).split("\n");
+            for (String line: lines) {
+                if (line.startsWith(">>> KDCCommunication")) {
+                    System.out.println(line);
+                    count--;
+                }
             }
-        }
-        if (count != 0) {
-            throw new Exception("Retry count is " + count + " less");
+            if (count != 0) {
+                throw new Exception("Retry count is " + count + " less");
+            }
+        } finally {
+            if (ss1 != null) ss1.close();
+            if (ss2 != null) ss2.close();
         }
     }
 }