0N/A/*
5740N/A * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/* @test
0N/A * @bug 4094891
0N/A * @summary unable to retry call if cached connection to server is used
0N/A * @library ../../../../java/rmi/testlibrary
5551N/A * @build TestLibrary JavaVM
0N/A * @run main/othervm DeadCachedConnection
0N/A */
0N/A
0N/A/* Fault: Cached connections used for remote invocations exhibited
0N/A * failure (sudden EOF or a TCP-related exception) immediately on
0N/A * sending a new request. It was then impossible to tell whether the
0N/A * connection had managed to transport the request before dying; even
0N/A * deserialization of request arguments is non-idempotent in general.
0N/A *
0N/A * In fact, this problem cannot be solved generally without rewriting
0N/A * the protocol. For now, the common case is the closing of an idle
0N/A * connection by a loaded/bored/dead server host.
0N/A *
0N/A * The fix is/was to trivially attempt to execute a non-blocking read
0N/A * on the connection before reusing it, to see if an exception/EOF is
0N/A * waiting for delivery. This is a 99%/1% solution, but until the
0N/A * great protocol rewrite, it's the best option.
0N/A *
0N/A * Reproducing is by establishing a connection to a registry and
0N/A * killing/restarting that registry (this forces the TCP connection
0N/A * to close). The next call to the registry will use the (stale)
0N/A * cached connection, and will fail without the bugfix.
0N/A */
0N/A
0N/Aimport java.io.*;
0N/Aimport java.rmi.*;
0N/Aimport java.rmi.registry.*;
0N/Aimport java.rmi.server.*;
0N/A
0N/Apublic class DeadCachedConnection {
5266N/A static public final int regport = TestLibrary.getUnusedRandomPort();
0N/A
0N/A static public void main(String[] argv)
0N/A throws Exception {
0N/A // establish the registry (we hope)
0N/A System.err.println ("Starting registry on port " + regport);
0N/A DeadCachedConnection.makeRegistry(regport);
0N/A
0N/A // Get a handle to the registry
0N/A Registry reg = null;
0N/A System.err.println ("Locating just-started registry...");
0N/A try {
0N/A reg = LocateRegistry.getRegistry(regport);
0N/A } catch (RemoteException e) {
0N/A throw new InternalError ("Can't find registry after starting it.");
0N/A }
0N/A
0N/A // Contact the registry by invoking something on it.
0N/A System.err.println ("Connecting to registry...");
0N/A String[] junk = reg.list();
0N/A
0N/A // Kill and restart the registry
0N/A System.err.println("Killing registry...");
0N/A DeadCachedConnection.killRegistry();
0N/A System.err.println("Restarting registry...");
0N/A DeadCachedConnection.makeRegistry(regport);
0N/A
0N/A // Try again (this is the test)
0N/A System.err.println("Trying to use registry in spite of stale cache...");
0N/A junk = reg.list();
0N/A
0N/A // we're happy
0N/A System.err.println("Test succeeded.");
0N/A try {
0N/A DeadCachedConnection.killRegistry();
0N/A } catch (Exception foo) {
0N/A }
0N/A }
0N/A
0N/A public static void makeRegistry(int p) {
0N/A // sadly, we can't kill a registry if we have too-close control
0N/A // over it. We must make it in a subprocess, and then kill the
0N/A // subprocess when it has served our needs.
0N/A
0N/A try {
0N/A JavaVM jvm =
0N/A new JavaVM("sun.rmi.registry.RegistryImpl", "", Integer.toString(p));
0N/A jvm.start();
5740N/A DeadCachedConnection.subreg = jvm;
0N/A
0N/A } catch (IOException e) {
0N/A // one of these is summarily dropped, can't remember which one
0N/A System.out.println ("Test setup failed - cannot run rmiregistry");
0N/A TestLibrary.bomb("Test setup failed - cannot run test", e);
0N/A }
0N/A // Slop - wait for registry to come up. This is stupid.
0N/A try {
0N/A Thread.sleep (5000);
0N/A } catch (Exception whatever) {
0N/A }
0N/A }
5740N/A private static JavaVM subreg = null;
0N/A
0N/A public static void killRegistry() {
0N/A if (DeadCachedConnection.subreg != null) {
0N/A DeadCachedConnection.subreg.destroy();
0N/A try { Thread.sleep(2000); } catch (InterruptedException ie) {}
0N/A }
0N/A DeadCachedConnection.subreg = null;
0N/A }
0N/A}