1 /* 2 * Copyright (c) 1998, 2013, 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 /* @test 25 * @bug 4094891 26 * @summary unable to retry call if cached connection to server is used 27 * @library ../../../../java/rmi/testlibrary 28 * @modules java.rmi/sun.rmi.registry 29 * java.rmi/sun.rmi.server 30 * java.rmi/sun.rmi.transport 31 * java.rmi/sun.rmi.transport.tcp 32 * @build TestLibrary JavaVM 33 * @run main/othervm DeadCachedConnection 34 */ 35 36 /* Fault: Cached connections used for remote invocations exhibited 37 * failure (sudden EOF or a TCP-related exception) immediately on 38 * sending a new request. It was then impossible to tell whether the 39 * connection had managed to transport the request before dying; even 40 * deserialization of request arguments is non-idempotent in general. 41 * 42 * In fact, this problem cannot be solved generally without rewriting 43 * the protocol. For now, the common case is the closing of an idle 44 * connection by a loaded/bored/dead server host. 45 * 46 * The fix is/was to trivially attempt to execute a non-blocking read 47 * on the connection before reusing it, to see if an exception/EOF is 48 * waiting for delivery. This is a 99%/1% solution, but until the 49 * great protocol rewrite, it's the best option. 50 * 51 * Reproducing is by establishing a connection to a registry and 52 * killing/restarting that registry (this forces the TCP connection 53 * to close). The next call to the registry will use the (stale) 54 * cached connection, and will fail without the bugfix. 55 */ 56 57 import java.io.*; 58 import java.rmi.*; 59 import java.rmi.registry.*; 60 import java.rmi.server.*; 61 62 public class DeadCachedConnection { 63 static public final int regport = TestLibrary.getUnusedRandomPort(); 64 65 static public void main(String[] argv) 66 throws Exception { 67 // establish the registry (we hope) 68 System.err.println ("Starting registry on port " + regport); 69 DeadCachedConnection.makeRegistry(regport); 70 71 // Get a handle to the registry 72 Registry reg = null; 73 System.err.println ("Locating just-started registry..."); 74 try { 75 reg = LocateRegistry.getRegistry(regport); 76 } catch (RemoteException e) { 77 throw new InternalError ("Can't find registry after starting it."); 78 } 79 80 // Contact the registry by invoking something on it. 81 System.err.println ("Connecting to registry..."); 82 String[] junk = reg.list(); 83 84 // Kill and restart the registry 85 System.err.println("Killing registry..."); 86 DeadCachedConnection.killRegistry(); 87 System.err.println("Restarting registry..."); 88 DeadCachedConnection.makeRegistry(regport); 89 90 // Try again (this is the test) 91 System.err.println("Trying to use registry in spite of stale cache..."); 92 junk = reg.list(); 93 94 // we're happy 95 System.err.println("Test succeeded."); 96 try { 97 DeadCachedConnection.killRegistry(); 98 } catch (Exception foo) { 99 } 100 } 101 102 public static void makeRegistry(int p) { 103 // sadly, we can't kill a registry if we have too-close control 104 // over it. We must make it in a subprocess, and then kill the 105 // subprocess when it has served our needs. 106 107 try { 108 JavaVM jvm = 109 new JavaVM("sun.rmi.registry.RegistryImpl", "", Integer.toString(p)); 110 jvm.start(); 111 DeadCachedConnection.subreg = jvm; 112 113 } catch (IOException e) { 114 // one of these is summarily dropped, can't remember which one 115 System.out.println ("Test setup failed - cannot run rmiregistry"); 116 TestLibrary.bomb("Test setup failed - cannot run test", e); 117 } 118 // Slop - wait for registry to come up. This is stupid. 119 try { 120 Thread.sleep (5000); 121 } catch (Exception whatever) { 122 } 123 } 124 private static JavaVM subreg = null; 125 126 public static void killRegistry() { 127 if (DeadCachedConnection.subreg != null) { 128 DeadCachedConnection.subreg.destroy(); 129 try { Thread.sleep(2000); } catch (InterruptedException ie) {} 130 } 131 DeadCachedConnection.subreg = null; 132 } 133 }