--- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/RMIMasterSocketFactory.java Sat May 14 08:03:03 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,468 +0,0 @@
-/*
- * Copyright (c) 1996, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-package sun.rmi.transport.proxy;
-
-import java.io.*;
-import java.net.*;
-import java.security.*;
-import java.util.*;
-import java.rmi.server.LogStream;
-import java.rmi.server.RMISocketFactory;
-import sun.rmi.runtime.Log;
-import sun.rmi.runtime.NewThreadAction;
-
-/**
- * RMIMasterSocketFactory attempts to create a socket connection to the
- * specified host using successively less efficient mechanisms
- * until one succeeds. If the host is successfully connected to,
- * the factory for the successful mechanism is stored in an internal
- * hash table keyed by the host name, so that future attempts to
- * connect to the same host will automatically use the same
- * mechanism.
- */
-@SuppressWarnings("deprecation")
-public class RMIMasterSocketFactory extends RMISocketFactory {
-
- /** "proxy" package log level */
- static int logLevel = LogStream.parseLevel(getLogLevel());
-
- private static String getLogLevel() {
- return java.security.AccessController.doPrivileged(
- (PrivilegedAction<String>) () -> System.getProperty("sun.rmi.transport.proxy.logLevel"));
- }
-
- /* proxy package log */
- static final Log proxyLog =
- Log.getLog("sun.rmi.transport.tcp.proxy",
- "transport", RMIMasterSocketFactory.logLevel);
-
- /** timeout for attemping direct socket connections */
- private static long connectTimeout = getConnectTimeout();
-
- private static long getConnectTimeout() {
- return java.security.AccessController.doPrivileged((PrivilegedAction<Long>) () ->
- Long.getLong("sun.rmi.transport.proxy.connectTimeout", 15000)); // default: 15 seconds
- }
-
- /** whether to fallback to HTTP on general connect failures */
- private static final boolean eagerHttpFallback =
- java.security.AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
- Boolean.getBoolean("sun.rmi.transport.proxy.eagerHttpFallback"));
-
- /** table of hosts successfully connected to and the factory used */
- private Hashtable<String, RMISocketFactory> successTable =
- new Hashtable<>();
-
- /** maximum number of hosts to remember successful connection to */
- private static final int MaxRememberedHosts = 64;
-
- /** list of the hosts in successTable in initial connection order */
- private Vector<String> hostList = new Vector<>(MaxRememberedHosts);
-
- /** default factory for initial use for direct socket connection */
- protected RMISocketFactory initialFactory = new RMIDirectSocketFactory();
-
- /** ordered list of factories to try as alternate connection
- * mechanisms if a direct socket connections fails */
- protected Vector<RMISocketFactory> altFactoryList;
-
- /**
- * Create a RMIMasterSocketFactory object. Establish order of
- * connection mechanisms to attempt on createSocket, if a direct
- * socket connection fails.
- */
- public RMIMasterSocketFactory() {
- altFactoryList = new Vector<>(2);
- boolean setFactories = false;
-
- try {
- String proxyHost;
- proxyHost = java.security.AccessController.doPrivileged(
- (PrivilegedAction<String>) () -> System.getProperty("http.proxyHost"));
-
- if (proxyHost == null)
- proxyHost = java.security.AccessController.doPrivileged(
- (PrivilegedAction<String>) () -> System.getProperty("proxyHost"));
-
- boolean disable = java.security.AccessController.doPrivileged(
- (PrivilegedAction<String>) () -> System.getProperty("java.rmi.server.disableHttp", "true"))
- .equalsIgnoreCase("true");
-
- if (!disable && proxyHost != null && proxyHost.length() > 0) {
- setFactories = true;
- }
- } catch (Exception e) {
- // unable to obtain the properties, so use the default behavior.
- }
-
- if (setFactories) {
- altFactoryList.addElement(new RMIHttpToPortSocketFactory());
- altFactoryList.addElement(new RMIHttpToCGISocketFactory());
- }
- }
-
- /**
- * Create a new client socket. If we remember connecting to this host
- * successfully before, then use the same factory again. Otherwise,
- * try using a direct socket connection and then the alternate factories
- * in the order specified in altFactoryList.
- */
- public Socket createSocket(String host, int port)
- throws IOException
- {
- if (proxyLog.isLoggable(Log.BRIEF)) {
- proxyLog.log(Log.BRIEF, "host: " + host + ", port: " + port);
- }
-
- /*
- * If we don't have any alternate factories to consult, short circuit
- * the fallback procedure and delegate to the initial factory.
- */
- if (altFactoryList.size() == 0) {
- return initialFactory.createSocket(host, port);
- }
-
- RMISocketFactory factory;
-
- /*
- * If we remember successfully connecting to this host before,
- * use the same factory.
- */
- factory = successTable.get(host);
- if (factory != null) {
- if (proxyLog.isLoggable(Log.BRIEF)) {
- proxyLog.log(Log.BRIEF,
- "previously successful factory found: " + factory);
- }
- return factory.createSocket(host, port);
- }
-
- /*
- * Next, try a direct socket connection. Open socket in another
- * thread and only wait for specified timeout, in case the socket
- * would otherwise spend minutes trying an unreachable host.
- */
- Socket initialSocket = null;
- Socket fallbackSocket = null;
- final AsyncConnector connector =
- new AsyncConnector(initialFactory, host, port,
- AccessController.getContext());
- // connection must be attempted with
- // this thread's access control context
- IOException initialFailure = null;
-
- try {
- synchronized (connector) {
-
- Thread t = java.security.AccessController.doPrivileged(
- new NewThreadAction(connector, "AsyncConnector", true));
- t.start();
-
- try {
- long now = System.currentTimeMillis();
- long deadline = now + connectTimeout;
- do {
- connector.wait(deadline - now);
- initialSocket = checkConnector(connector);
- if (initialSocket != null)
- break;
- now = System.currentTimeMillis();
- } while (now < deadline);
- } catch (InterruptedException e) {
- throw new InterruptedIOException(
- "interrupted while waiting for connector");
- }
- }
-
- // assume no route to host (for now) if no connection yet
- if (initialSocket == null)
- throw new NoRouteToHostException(
- "connect timed out: " + host);
-
- proxyLog.log(Log.BRIEF, "direct socket connection successful");
-
- return initialSocket;
-
- } catch (UnknownHostException | NoRouteToHostException e) {
- initialFailure = e;
- } catch (SocketException e) {
- if (eagerHttpFallback) {
- initialFailure = e;
- } else {
- throw e;
- }
- } finally {
- if (initialFailure != null) {
-
- if (proxyLog.isLoggable(Log.BRIEF)) {
- proxyLog.log(Log.BRIEF,
- "direct socket connection failed: ", initialFailure);
- }
-
- // Finally, try any alternate connection mechanisms.
- for (int i = 0; i < altFactoryList.size(); ++ i) {
- factory = altFactoryList.elementAt(i);
- if (proxyLog.isLoggable(Log.BRIEF)) {
- proxyLog.log(Log.BRIEF,
- "trying with factory: " + factory);
- }
- try (Socket testSocket =
- factory.createSocket(host, port)) {
- // For HTTP connections, the output (POST request) must
- // be sent before we verify a successful connection.
- // So, sacrifice a socket for the sake of testing...
- // The following sequence should verify a successful
- // HTTP connection if no IOException is thrown.
- InputStream in = testSocket.getInputStream();
- int b = in.read(); // probably -1 for EOF...
- } catch (IOException ex) {
- if (proxyLog.isLoggable(Log.BRIEF)) {
- proxyLog.log(Log.BRIEF, "factory failed: ", ex);
- }
-
- continue;
- }
- proxyLog.log(Log.BRIEF, "factory succeeded");
-
- // factory succeeded, open new socket for caller's use
- try {
- fallbackSocket = factory.createSocket(host, port);
- } catch (IOException ex) { // if it fails 2nd time,
- } // just give up
- break;
- }
- }
- }
-
- synchronized (successTable) {
- try {
- // check once again to see if direct connection succeeded
- synchronized (connector) {
- initialSocket = checkConnector(connector);
- }
- if (initialSocket != null) {
- // if we had made another one as well, clean it up...
- if (fallbackSocket != null)
- fallbackSocket.close();
- return initialSocket;
- }
- // if connector ever does get socket, it won't be used
- connector.notUsed();
- } catch (UnknownHostException | NoRouteToHostException e) {
- initialFailure = e;
- } catch (SocketException e) {
- if (eagerHttpFallback) {
- initialFailure = e;
- } else {
- throw e;
- }
- }
- // if we had found an alternate mechanism, go and use it
- if (fallbackSocket != null) {
- // remember this successful host/factory pair
- rememberFactory(host, factory);
- return fallbackSocket;
- }
- throw initialFailure;
- }
- }
-
- /**
- * Remember a successful factory for connecting to host.
- * Currently, excess hosts are removed from the remembered list
- * using a Least Recently Created strategy.
- */
- void rememberFactory(String host, RMISocketFactory factory) {
- synchronized (successTable) {
- while (hostList.size() >= MaxRememberedHosts) {
- successTable.remove(hostList.elementAt(0));
- hostList.removeElementAt(0);
- }
- hostList.addElement(host);
- successTable.put(host, factory);
- }
- }
-
- /**
- * Check if an AsyncConnector succeeded. If not, return socket
- * given to fall back to.
- */
- Socket checkConnector(AsyncConnector connector)
- throws IOException
- {
- Exception e = connector.getException();
- if (e != null) {
- e.fillInStackTrace();
- /*
- * The AsyncConnector implementation guaranteed that the exception
- * will be either an IOException or a RuntimeException, and we can
- * only throw one of those, so convince that compiler that it must
- * be one of those.
- */
- if (e instanceof IOException) {
- throw (IOException) e;
- } else if (e instanceof RuntimeException) {
- throw (RuntimeException) e;
- } else {
- throw new Error("internal error: " +
- "unexpected checked exception: " + e.toString());
- }
- }
- return connector.getSocket();
- }
-
- /**
- * Create a new server socket.
- */
- public ServerSocket createServerSocket(int port) throws IOException {
- //return new HttpAwareServerSocket(port);
- return initialFactory.createServerSocket(port);
- }
-
-
- /**
- * AsyncConnector is used by RMIMasterSocketFactory to attempt socket
- * connections on a separate thread. This allows RMIMasterSocketFactory
- * to control how long it will wait for the connection to succeed.
- */
- private class AsyncConnector implements Runnable {
-
- /** what factory to use to attempt connection */
- private RMISocketFactory factory;
-
- /** the host to connect to */
- private String host;
-
- /** the port to connect to */
- private int port;
-
- /** access control context to attempt connection within */
- private AccessControlContext acc;
-
- /** exception that occurred during connection, if any */
- private Exception exception = null;
-
- /** the connected socket, if successful */
- private Socket socket = null;
-
- /** socket should be closed after created, if ever */
- private boolean cleanUp = false;
-
- /**
- * Create a new asynchronous connector object.
- */
- AsyncConnector(RMISocketFactory factory, String host, int port,
- AccessControlContext acc)
- {
- this.factory = factory;
- this.host = host;
- this.port = port;
- this.acc = acc;
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkConnect(host, port);
- }
- }
-
- /**
- * Attempt socket connection in separate thread. If successful,
- * notify master waiting,
- */
- public void run() {
- try {
- /*
- * Using the privileges of the thread that wants to make the
- * connection is tempting, but it will fail with applets with
- * the current applet security manager because the applet
- * network connection policy is not captured in the permission
- * framework of the access control context we have.
- *
- * java.security.AccessController.beginPrivileged(acc);
- */
- try {
- Socket temp = factory.createSocket(host, port);
- synchronized (this) {
- socket = temp;
- notify();
- }
- rememberFactory(host, factory);
- synchronized (this) {
- if (cleanUp)
- try {
- socket.close();
- } catch (IOException e) {
- }
- }
- } catch (Exception e) {
- /*
- * Note that the only exceptions which could actually have
- * occurred here are IOException or RuntimeException.
- */
- synchronized (this) {
- exception = e;
- notify();
- }
- }
- } finally {
- /*
- * See above comments for matching beginPrivileged() call that
- * is also commented out.
- *
- * java.security.AccessController.endPrivileged();
- */
- }
- }
-
- /**
- * Get exception that occurred during connection attempt, if any.
- * In the current implementation, this is guaranteed to be either
- * an IOException or a RuntimeException.
- */
- private synchronized Exception getException() {
- return exception;
- }
-
- /**
- * Get successful socket, if any.
- */
- private synchronized Socket getSocket() {
- return socket;
- }
-
- /**
- * Note that this connector's socket, if ever successfully created,
- * will not be used, so it should be cleaned up quickly
- */
- synchronized void notUsed() {
- if (socket != null) {
- try {
- socket.close();
- } catch (IOException e) {
- }
- }
- cleanUp = true;
- }
- }
-}