787 lines · 26.4 KB · Java
RawDownload
/* * Copyright (c) 1996, 2005, 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.tcp; import java.io.DataInput;import java.io.DataOutput;import java.io.IOException;import java.io.ObjectInput;import java.io.ObjectOutput;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;import java.rmi.ConnectIOException;import java.rmi.RemoteException;import java.rmi.server.RMIClientSocketFactory;import java.rmi.server.RMIServerSocketFactory;import java.rmi.server.RMISocketFactory;import java.security.AccessController;import java.util.Collection;import java.util.HashMap;import java.util.HashSet;import java.util.LinkedList;import java.util.Map;import java.util.Set;import sun.rmi.runtime.Log;import sun.rmi.runtime.NewThreadAction;import sun.rmi.transport.Channel;import sun.rmi.transport.Endpoint;import sun.rmi.transport.Target;import sun.rmi.transport.Transport;import sun.security.action.GetBooleanAction;import sun.security.action.GetIntegerAction;import sun.security.action.GetPropertyAction; /** * TCPEndpoint represents some communication endpoint for an address * space (VM). * * @author Ann Wollrath */public class TCPEndpoint implements Endpoint {    /** IP address or host name */    private String host;    /** port number */    private int port;    /** custom client socket factory (null if not custom factory) */    private final RMIClientSocketFactory csf;    /** custom server socket factory (null if not custom factory) */    private final RMIServerSocketFactory ssf;     /** if local, the port number to listen on */    private int listenPort = -1;    /** if local, the transport object associated with this endpoint */    private TCPTransport transport = null;     /** the local host name */    private static String localHost;    /** true if real local host name is known yet */    private static boolean localHostKnown;     // this should be a *private* method since it is privileged    private static int getInt(String name, int def) {        return AccessController.doPrivileged(new GetIntegerAction(name, def));    }     // this should be a *private* method since it is privileged    private static boolean getBoolean(String name) {        return AccessController.doPrivileged(new GetBooleanAction(name));    }     /**     * Returns the value of the java.rmi.server.hostname property.     */    private static String getHostnameProperty() {        return AccessController.doPrivileged(            new GetPropertyAction("java.rmi.server.hostname"));    }     /**     * Find host name of local machine.  Property "java.rmi.server.hostname"     * is used if set, so server administrator can compensate for the possible     * inablility to get fully qualified host name from VM.     */    static {        localHostKnown = true;        localHost = getHostnameProperty();         // could try querying CGI program here?        if (localHost == null) {            try {                InetAddress localAddr = InetAddress.getLocalHost();                byte[] raw = localAddr.getAddress();                if ((raw[0] == 127) &&                    (raw[1] ==   0) &&                    (raw[2] ==   0) &&                    (raw[3] ==   1)) {                    localHostKnown = false;                }                 /* if the user wishes to use a fully qualified domain                 * name then attempt to find one.                 */                if (getBoolean("java.rmi.server.useLocalHostName")) {                    localHost = FQDN.attemptFQDN(localAddr);                } else {                    /* default to using ip addresses, names will                     * work across seperate domains.                     */                    localHost = localAddr.getHostAddress();                }            } catch (Exception e) {                localHostKnown = false;                localHost = null;            }        }         if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) {            TCPTransport.tcpLog.log(Log.BRIEF,                "localHostKnown = " + localHostKnown +                ", localHost = " + localHost);        }    }     /** maps an endpoint key containing custom socket factories to     * their own unique endpoint */    // TBD: should this be a weak hash table?    private static final        Map<TCPEndpoint,LinkedList<TCPEndpoint>> localEndpoints =        new HashMap<TCPEndpoint,LinkedList<TCPEndpoint>>();     /**     * Create an endpoint for a specified host and port.     * This should not be used by external classes to create endpoints     * for servers in this VM; use getLocalEndpoint instead.     */    public TCPEndpoint(String host, int port) {        this(host, port, null, null);    }     /**     * Create a custom socket factory endpoint for a specified host and port.     * This should not be used by external classes to create endpoints     * for servers in this VM; use getLocalEndpoint instead.     */    public TCPEndpoint(String host, int port, RMIClientSocketFactory csf,                       RMIServerSocketFactory ssf)    {        if (host == null)            host = "";        this.host = host;        this.port = port;        this.csf = csf;        this.ssf = ssf;    }     /**     * Get an endpoint for the local address space on specified port.     * If port number is 0, it returns shared default endpoint object     * whose host name and port may or may not have been determined.     */    public static TCPEndpoint getLocalEndpoint(int port) {        return getLocalEndpoint(port, null, null);    }     public static TCPEndpoint getLocalEndpoint(int port,                                               RMIClientSocketFactory csf,                                               RMIServerSocketFactory ssf)    {        /*         * Find mapping for an endpoint key to the list of local unique         * endpoints for this client/server socket factory pair (perhaps         * null) for the specific port.         */        TCPEndpoint ep = null;         synchronized (localEndpoints) {            TCPEndpoint endpointKey = new TCPEndpoint(null, port, csf, ssf);            LinkedList<TCPEndpoint> epList = localEndpoints.get(endpointKey);            String localHost = resampleLocalHost();             if (epList == null) {                /*                 * Create new endpoint list.                 */                ep = new TCPEndpoint(localHost, port, csf, ssf);                epList = new LinkedList<TCPEndpoint>();                epList.add(ep);                ep.listenPort = port;                ep.transport = new TCPTransport(epList);                localEndpoints.put(endpointKey, epList);                 if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) {                    TCPTransport.tcpLog.log(Log.BRIEF,                        "created local endpoint for socket factory " + ssf +                        " on port " + port);                }            } else {                synchronized (epList) {                    ep = epList.getLast();                    String lastHost = ep.host;                    int lastPort =  ep.port;                    TCPTransport lastTransport = ep.transport;                    // assert (localHost == null ^ lastHost != null)                    if (localHost != null && !localHost.equals(lastHost)) {                        /*                         * Hostname has been updated; add updated endpoint                         * to list.                         */                        if (lastPort != 0) {                            /*                             * Remove outdated endpoints only if the                             * port has already been set on those endpoints.                             */                            epList.clear();                        }                        ep = new TCPEndpoint(localHost, lastPort, csf, ssf);                        ep.listenPort = port;                        ep.transport = lastTransport;                        epList.add(ep);                    }                }            }        }         return ep;    }     /**     * Resamples the local hostname and returns the possibly-updated     * local hostname.     */    private static String resampleLocalHost() {         String hostnameProperty = getHostnameProperty();         synchronized (localEndpoints) {            // assert(localHostKnown ^ (localHost == null))             if (hostnameProperty != null) {                if (!localHostKnown) {                    /*                     * If the local hostname is unknown, update ALL                     * existing endpoints with the new hostname.                     */                    setLocalHost(hostnameProperty);                } else if (!hostnameProperty.equals(localHost)) {                    /*                     * Only update the localHost field for reference                     * in future endpoint creation.                     */                    localHost = hostnameProperty;                     if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) {                        TCPTransport.tcpLog.log(Log.BRIEF,                            "updated local hostname to: " + localHost);                    }                }            }            return localHost;        }    }     /**     * Set the local host name, if currently unknown.     */    static void setLocalHost(String host) {        // assert (host != null)         synchronized (localEndpoints) {            /*             * If host is not known, change the host field of ALL             * the local endpoints.             */            if (!localHostKnown) {                localHost = host;                localHostKnown = true;                 if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) {                    TCPTransport.tcpLog.log(Log.BRIEF,                        "local host set to " + host);                }                for (LinkedList<TCPEndpoint> epList : localEndpoints.values())                {                    synchronized (epList) {                        for (TCPEndpoint ep : epList) {                            ep.host = host;                        }                    }                }            }        }    }     /**     * Set the port of the (shared) default endpoint object.     * When first created, it contains port 0 because the transport     * hasn't tried to listen to get assigned a port, or if listening     * failed, a port hasn't been assigned from the server.     */    static void setDefaultPort(int port, RMIClientSocketFactory csf,                               RMIServerSocketFactory ssf)    {        TCPEndpoint endpointKey = new TCPEndpoint(null, 0, csf, ssf);         synchronized (localEndpoints) {            LinkedList<TCPEndpoint> epList = localEndpoints.get(endpointKey);             synchronized (epList) {                int size = epList.size();                TCPEndpoint lastEp = epList.getLast();                 for (TCPEndpoint ep : epList) {                    ep.port = port;                }                if (size > 1) {                    /*                     * Remove all but the last element of the list                     * (which contains the most recent hostname).                     */                    epList.clear();                    epList.add(lastEp);                }            }             /*             * Allow future exports to use the actual bound port             * explicitly (see 6269166).             */            TCPEndpoint newEndpointKey = new TCPEndpoint(null, port, csf, ssf);            localEndpoints.put(newEndpointKey, epList);             if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) {                TCPTransport.tcpLog.log(Log.BRIEF,                    "default port for server socket factory " + ssf +                    " and client socket factory " + csf +                    " set to " + port);            }        }    }     /**     * Returns transport for making connections to remote endpoints;     * (here, the default transport at port 0 is used).     */    public Transport getOutboundTransport() {        TCPEndpoint localEndpoint = getLocalEndpoint(0, null, null);        return localEndpoint.transport;    }     /**     * Returns the current list of known transports.     * The returned list is an unshared collection of Transports,     * including all transports which may have channels to remote     * endpoints.     */    private static Collection<TCPTransport> allKnownTransports() {        // Loop through local endpoints, getting the transport of each one.        Set<TCPTransport> s;        synchronized (localEndpoints) {            // presize s to number of localEndpoints            s = new HashSet<TCPTransport>(localEndpoints.size());            for (LinkedList<TCPEndpoint> epList : localEndpoints.values()) {                /*                 * Each local endpoint has its transport added to s.                 * Note: the transport is the same for all endpoints                 * in the list, so it is okay to pick any one of them.                 */                TCPEndpoint ep = epList.getFirst();                s.add(ep.transport);            }        }        return s;    }     /**     * Release idle outbound connections to reduce demand on I/O resources.     * All transports are asked to release excess connections.     */    public static void shedConnectionCaches() {        for (TCPTransport transport : allKnownTransports()) {            transport.shedConnectionCaches();        }    }     /**     * Export the object to accept incoming calls.     */    public void exportObject(Target target) throws RemoteException {        transport.exportObject(target);    }     /**     * Returns a channel for this (remote) endpoint.     */    public Channel getChannel() {        return getOutboundTransport().getChannel(this);    }     /**     * Returns address for endpoint     */    public String getHost() {        return host;    }     /**     * Returns the port for this endpoint.  If this endpoint was     * created as a server endpoint (using getLocalEndpoint) for a     * default/anonymous port and its inbound transport has started     * listening, this method returns (instead of zero) the actual     * bound port suitable for passing to clients.     **/    public int getPort() {        return port;    }     /**     * Returns the port that this endpoint's inbound transport listens     * on, if this endpoint was created as a server endpoint (using     * getLocalEndpoint).  If this endpoint was created for the     * default/anonymous port, then this method returns zero even if     * the transport has started listening.     **/    public int getListenPort() {        return listenPort;    }     /**     * Returns the transport for incoming connections to this     * endpoint, if this endpoint was created as a server endpoint     * (using getLocalEndpoint).     **/    public Transport getInboundTransport() {        return transport;    }     /**     * Get the client socket factory associated with this endpoint.     */    public RMIClientSocketFactory getClientSocketFactory() {        return csf;    }     /**     * Get the server socket factory associated with this endpoint.     */    public RMIServerSocketFactory getServerSocketFactory() {        return ssf;    }     /**     * Return string representation for endpoint.     */    public String toString() {        return "[" + host + ":" + port +            (ssf != null ? "," + ssf : "") +            (csf != null ? "," + csf : "") +            "]";    }     public int hashCode() {        return port;    }     public boolean equals(Object obj) {        if ((obj != null) && (obj instanceof TCPEndpoint)) {            TCPEndpoint ep = (TCPEndpoint) obj;            if (port != ep.port || !host.equals(ep.host))                return false;            if (((csf == null) ^ (ep.csf == null)) ||                ((ssf == null) ^ (ep.ssf == null)))                return false;            /*             * Fix for 4254510: perform socket factory *class* equality check             * before socket factory equality check to avoid passing             * a potentially naughty socket factory to this endpoint's             * {client,server} socket factory equals method.             */

Lines 1–500 of 787.