8162521: java/net/Authenticator/B4933582.sh fails intermittently with BindException
authorxiaofeya
Thu, 01 Dec 2016 06:54:01 -0800
changeset 42342 63783438fd88
parent 42341 10ef69aa7e92
child 42343 58076b66ffdb
child 42730 9ed3ac7896dc
8162521: java/net/Authenticator/B4933582.sh fails intermittently with BindException Reviewed-by: dfuchs
jdk/test/java/net/Authenticator/B4933582.java
jdk/test/java/net/Authenticator/B4933582.sh
jdk/test/sun/net/www/httptest/TestHttpServer.java
--- a/jdk/test/java/net/Authenticator/B4933582.java	Thu Dec 01 06:38:46 2016 -0800
+++ b/jdk/test/java/net/Authenticator/B4933582.java	Thu Dec 01 06:54:01 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -21,6 +21,15 @@
  * questions.
  */
 
+/*
+ * @test
+ * @bug 4933582
+ * @library ../../../sun/net/www/httptest
+ * @modules java.base/sun.net.www
+ *          java.base/sun.net.www.protocol.http
+ * @build HttpCallback HttpTransaction TestHttpServer B4933582
+ * @run main/othervm B4933582
+ */
 import java.io.*;
 import java.net.*;
 import java.util.*;
@@ -44,7 +53,7 @@
         req.orderlyClose();
     }
 
-    static boolean firstTime = true;
+    static volatile boolean firstTime = true;
 
     public void request (HttpTransaction req) {
         try {
@@ -114,43 +123,67 @@
         URL url = new URL (u);
         System.out.println ("client opening connection to: " + u);
         URLConnection urlc = url.openConnection ();
-        InputStream is = urlc.getInputStream ();
-        read (is);
-        is.close();
+        try(InputStream is = urlc.getInputStream ()) {
+            read (is);
+        }
     }
 
     static TestHttpServer server;
 
     public static void main (String[] args) throws Exception {
-        firstTime = args[0].equals ("first");
         MyAuthenticator auth = new MyAuthenticator ();
         Authenticator.setDefault (auth);
         CacheImpl cache;
         try {
-            if (firstTime) {
-                server = new TestHttpServer (new B4933582(), 1, 10, 0);
-                cache = new CacheImpl (server.getLocalPort());
-            } else {
-                cache = new CacheImpl ();
-                server = new TestHttpServer(new B4933582(), 1, 10, cache.getPort());
-            }
+            server = new TestHttpServer (new B4933582(), 1, 10, 0);
+            cache = new CacheImpl (server.getLocalPort());
             AuthCacheValue.setAuthCache (cache);
-            System.out.println ("Server: listening on port: " + server.getLocalPort());
             client ("http://localhost:"+server.getLocalPort()+"/d1/foo.html");
-        } catch (Exception e) {
+        } finally {
             if (server != null) {
                 server.terminate();
             }
-            throw e;
         }
+
         int f = auth.getCount();
-        if (firstTime && f != 1) {
-            except ("Authenticator was called "+f+" times. Should be 1");
+        if (f != 1) {
+            except("Authenticator was called " + f + " times. Should be 1");
         }
-        if (!firstTime && f != 0) {
-            except ("Authenticator was called "+f+" times. Should be 0");
+
+        firstTime = false;
+
+        int retries = 0;
+        cache = new CacheImpl();
+        while (true) {
+            try {
+                server = new TestHttpServer(new B4933582(), 1, 10,
+                        cache.getPort());
+                break;
+            } catch (BindException e) {
+                if (retries++ < 5) {
+                    Thread.sleep(200L);
+                    System.out.println("BindException \"" + e.getMessage()
+                            + "\", retrying...");
+                    continue;
+                } else {
+                    throw e;
+                }
+            }
         }
-        server.terminate();
+
+        try {
+            AuthCacheValue.setAuthCache(cache);
+            client("http://localhost:" + server.getLocalPort() + "/d1/foo.html");
+        } finally {
+            if (server != null) {
+                server.terminate();
+            }
+        }
+
+        f = auth.getCount();
+        if (f != 1) {
+            except("Authenticator was called " + f + " times. Should be 1");
+        }
     }
 
     public static void except (String s) {
@@ -163,7 +196,7 @@
             super ();
         }
 
-        int count = 0;
+        volatile int count = 0;
 
         public PasswordAuthentication getPasswordAuthentication () {
             PasswordAuthentication pw;
@@ -178,7 +211,7 @@
     }
 
     static class CacheImpl extends AuthCacheImpl {
-        HashMap map;
+        HashMap<String,LinkedList<AuthCacheValue>> map;
         int port; // need to store the port number the server is using
 
         CacheImpl () throws IOException {
@@ -190,20 +223,18 @@
             this.port = port;
             File src = new File ("cache.ser");
             if (src.exists()) {
-                ObjectInputStream is = new ObjectInputStream (
-                    new FileInputStream (src)
-                );
-                try {
-                    map = (HashMap)is.readObject ();
+                try (ObjectInputStream is = new ObjectInputStream(
+                        new FileInputStream(src))) {
+                    map = (HashMap<String,LinkedList<AuthCacheValue>>)is
+                              .readObject();
                     this.port = (Integer)is.readObject ();
                     System.out.println ("read port from file " + port);
                 } catch (ClassNotFoundException e) {
                     assert false;
                 }
-                is.close();
                 System.out.println ("setMap from cache.ser");
             } else {
-                map = new HashMap();
+                map = new HashMap<>();
             }
             setMap (map);
         }
@@ -213,20 +244,22 @@
         }
 
         private void writeMap () {
+            File dst = new File("cache.ser");
             try {
-                File dst = new File ("cache.ser");
                 dst.delete();
                 if (!dst.createNewFile()) {
                     return;
                 }
-                ObjectOutputStream os = new ObjectOutputStream (
-                        new FileOutputStream (dst)
-                );
+            } catch (IOException e) {
+            }
+
+            try (ObjectOutputStream os = new ObjectOutputStream(
+                    new FileOutputStream(dst))) {
                 os.writeObject(map);
                 os.writeObject(port);
-                System.out.println ("wrote port " + port);
-                os.close();
-            } catch (IOException e) {}
+                System.out.println("wrote port " + port);
+            } catch (IOException e) {
+            }
         }
 
         public void put (String pkey, AuthCacheValue value) {
--- a/jdk/test/java/net/Authenticator/B4933582.sh	Thu Dec 01 06:38:46 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-#
-# Copyright (c) 2003, 2013, 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 4933582
-
-OS=`uname -s`
-case "$OS" in
-  SunOS | Linux | Darwin | AIX )
-    PS=":"
-    FS="/"
-    ;;
-  CYGWIN* )
-    PS=";"
-    FS="/"
-    ;;
-  Windows* )
-    PS=";"
-    FS="\\"
-    ;;
-  * )
-    echo "Unrecognized system!"
-    exit 1;
-    ;;
-esac
-
-EXTRAOPTS="--add-exports java.base/sun.net.www=ALL-UNNAMED --add-exports java.base/sun.net.www.protocol.http=ALL-UNNAMED"
-export EXTRAOPTS
-
-${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . \
-    -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest" ${TESTSRC}${FS}B4933582.java
-rm -f cache.ser auth.save
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 first
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 second
--- a/jdk/test/sun/net/www/httptest/TestHttpServer.java	Thu Dec 01 06:38:46 2016 -0800
+++ b/jdk/test/sun/net/www/httptest/TestHttpServer.java	Thu Dec 01 06:54:01 2016 -0800
@@ -116,15 +116,26 @@
         }
     }
 
-    /** Tell all threads in the server to exit within 5 seconds.
-     *  This is an abortive termination. Just prior to the thread exiting
-     *  all channels in that thread waiting to be closed are forceably closed.
+    /**
+     * Tell all threads in the server to exit within 5 seconds.
+     * This is an abortive termination. Just prior to the thread exiting
+     * all channels in that thread waiting to be closed are forceably closed.
+     * @throws InterruptedException
      */
 
     public void terminate () {
         for (int i=0; i<threads; i++) {
             servers[i].terminate ();
         }
+
+        for (int i = 0; i < threads; i++) {
+            try {
+                servers[i].join();
+            } catch (InterruptedException e) {
+                System.err.println("Unexpected InterruptedException during terminating server");
+                throw new RuntimeException(e);
+            }
+        }
     }
 
     /**
@@ -147,7 +158,7 @@
         int maxconn;
         int nconn;
         ClosedChannelList clist;
-        boolean shutdown;
+        volatile boolean shutdown;
 
         Server (HttpCallback cb, ServerSocketChannel schan, int maxconn) {
             this.schan = schan;
@@ -166,18 +177,18 @@
         }
 
         /* Stop the thread as soon as possible */
-        public synchronized void terminate () {
+        public void terminate () {
             shutdown = true;
         }
 
         public void run ()  {
             try {
                 while (true) {
-                    selector.select (1000);
-                    Set selected = selector.selectedKeys();
-                    Iterator iter = selected.iterator();
+                    selector.select(1000);
+                    Set<SelectionKey> selected = selector.selectedKeys();
+                    Iterator<SelectionKey> iter = selected.iterator();
                     while (iter.hasNext()) {
-                        key = (SelectionKey)iter.next();
+                        key = iter.next();
                         if (key.equals (listenerKey)) {
                             SocketChannel sock = schan.accept ();
                             if (sock == null) {
@@ -200,7 +211,7 @@
                                 SocketChannel chan = (SocketChannel) key.channel();
                                 System.out.println("SERVER: connection readable. chan[" + chan + "]");
                                 if (key.attachment() != null) {
-                                    System.out.println("Server: comsume");
+                                    System.out.println("Server: consume");
                                     closed = consume (chan);
                                 } else {
                                     closed = read (chan, key);
@@ -219,7 +230,16 @@
                     }
                     clist.check();
                     if (shutdown) {
+                        System.out.println("Force to Shutdown");
+                        SelectionKey sKey = schan.keyFor(selector);
+                        if (sKey != null) {
+                            sKey.cancel();
+                        }
+
                         clist.terminate ();
+                        selector.close();
+                        schan.socket().close();
+                        schan.close();
                         return;
                     }
                 }
@@ -726,3 +746,4 @@
         }
     }
 }
+