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