| /* | |
| * Copyright (c) 1996, 2022, 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; | |
| import java.io.IOException; | |
| import java.io.ObjectInput; | |
| import java.io.ObjectOutput; | |
| import java.rmi.Remote; | |
| import java.rmi.RemoteException; | |
| import java.rmi.server.ObjID; | |
| import java.rmi.server.RMIClientSocketFactory; | |
| import java.rmi.server.RMIServerSocketFactory; | |
| import java.util.Arrays; | |
| import sun.rmi.transport.tcp.TCPEndpoint; | |
| /** | |
| * NOTE: There is a JDK-internal dependency on the existence of this | |
| * class and its getClientSocketFactory method in the implementation | |
| * of javax.management.remote.rmi.RMIConnector. | |
| **/ | |
| public class LiveRef implements Cloneable { | |
| /** wire representation for the object*/ | |
| private final Endpoint ep; | |
| private final ObjID id; | |
| /** cached connection service for the object */ | |
| private transient Channel ch; | |
| /** flag to indicate whether this ref specifies a local server or | |
| * is a ref for a remote object (surrogate) | |
| */ | |
| private final boolean isLocal; | |
| /** | |
| * Construct a "well-known" live reference to a remote object | |
| * @param isLocal If true, indicates this ref specifies a local | |
| * server in this address space; if false, the ref is for a remote | |
| * object (hence a surrogate or proxy) in another address space. | |
| */ | |
| public LiveRef(ObjID objID, Endpoint endpoint, boolean isLocal) { | |
| ep = endpoint; | |
| id = objID; | |
| this.isLocal = isLocal; | |
| } | |
| /** | |
| * Construct a new live reference for a server object in the local | |
| * address space. | |
| */ | |
| public LiveRef(int port) { | |
| this((new ObjID()), port); | |
| } | |
| /** | |
| * Construct a new live reference for a server object in the local | |
| * address space, to use sockets of the specified type. | |
| */ | |
| public LiveRef(int port, | |
| RMIClientSocketFactory csf, | |
| RMIServerSocketFactory ssf) | |
| { | |
| this((new ObjID()), port, csf, ssf); | |
| } | |
| /** | |
| * Construct a new live reference for a "well-known" server object | |
| * in the local address space. | |
| */ | |
| public LiveRef(ObjID objID, int port) { | |
| this(objID, TCPEndpoint.getLocalEndpoint(port), true); | |
| } | |
| /** | |
| * Construct a new live reference for a "well-known" server object | |
| * in the local address space, to use sockets of the specified type. | |
| */ | |
| public LiveRef(ObjID objID, int port, RMIClientSocketFactory csf, | |
| RMIServerSocketFactory ssf) | |
| { | |
| this(objID, TCPEndpoint.getLocalEndpoint(port, csf, ssf), true); | |
| } | |
| /** | |
| * Return a shallow copy of this ref. | |
| */ | |
| public Object clone() { | |
| try { | |
| LiveRef newRef = (LiveRef) super.clone(); | |
| return newRef; | |
| } catch (CloneNotSupportedException e) { | |
| throw new InternalError(e.toString(), e); | |
| } | |
| } | |
| /** | |
| * Return the port number associated with this ref. | |
| */ | |
| public int getPort() { | |
| return ((TCPEndpoint) ep).getPort(); | |
| } | |
| /** | |
| * Return the client socket factory associated with this ref. | |
| * | |
| * NOTE: There is a JDK-internal dependency on the existence of | |
| * this method in the implementation of | |
| * javax.management.remote.rmi.RMIConnector. | |
| **/ | |
| public RMIClientSocketFactory getClientSocketFactory() { | |
| return ((TCPEndpoint) ep).getClientSocketFactory(); | |
| } | |
| /** | |
| * Return the server socket factory associated with this ref. | |
| */ | |
| public RMIServerSocketFactory getServerSocketFactory() { | |
| return ((TCPEndpoint) ep).getServerSocketFactory(); | |
| } | |
| /** | |
| * Export the object to accept incoming calls. | |
| */ | |
| public void exportObject(Target target) throws RemoteException { | |
| ep.exportObject(target); | |
| } | |
| public Channel getChannel() throws RemoteException { | |
| if (ch == null) { | |
| ch = ep.getChannel(); | |
| } | |
| return ch; | |
| } | |
| public ObjID getObjID() { | |
| return id; | |
| } | |
| Endpoint getEndpoint() { | |
| return ep; | |
| } | |
| public String toString() { | |
| String type; | |
| if (isLocal) | |
| type = "local"; | |
| else | |
| type = "remote"; | |
| return "[endpoint:" + ep + "(" + type + ")," + | |
| "objID:" + id + "]"; | |
| } | |
| public int hashCode() { | |
| return id.hashCode(); | |
| } | |
| public boolean equals(Object obj) { | |
| if (obj instanceof LiveRef ref) { | |
| return (ep.equals(ref.ep) && id.equals(ref.id) && | |
| isLocal == ref.isLocal); | |
| } else { | |
| return false; | |
| } | |
| } | |
| public boolean remoteEquals(Object obj) { | |
| if (obj instanceof LiveRef ref) { | |
| TCPEndpoint thisEp = ((TCPEndpoint) ep); | |
| TCPEndpoint refEp = ((TCPEndpoint) ref.ep); | |
| RMIClientSocketFactory thisClientFactory = | |
| thisEp.getClientSocketFactory(); | |
| RMIClientSocketFactory refClientFactory = | |
| refEp.getClientSocketFactory(); | |
| /** | |
| * Fix for 4254103: LiveRef.remoteEquals should not fail | |
| * if one of the objects in the comparison has a null | |
| * server socket. Comparison should only consider the | |
| * following criteria: | |
| * | |
| * hosts, ports, client socket factories and object IDs. | |
| */ | |
| if (thisEp.getPort() != refEp.getPort() || | |
| !thisEp.getHost().equals(refEp.getHost())) | |
| { | |
| return false; | |
| } | |
| if ((thisClientFactory == null) ^ (refClientFactory == null)) { | |
| return false; | |
| } | |
| if ((thisClientFactory != null) && | |
| !((thisClientFactory.getClass() == | |
| refClientFactory.getClass()) && | |
| (thisClientFactory.equals(refClientFactory)))) | |
| { | |
| return false; | |
| } | |
| return (id.equals(ref.id)); | |
| } else { | |
| return false; | |
| } | |
| } | |
| public void write(ObjectOutput out, boolean useNewFormat) | |
| throws IOException | |
| { | |
| boolean isResultStream = false; | |
| if (out instanceof ConnectionOutputStream) { | |
| ConnectionOutputStream stream = (ConnectionOutputStream) out; | |
| isResultStream = stream.isResultStream(); | |
| /* | |
| * Ensure that referential integrity is not broken while | |
| * this LiveRef is in transit. If it is being marshalled | |
| * as part of a result, it may not otherwise be strongly | |
| * reachable after the remote call has completed; even if | |
| * it is being marshalled as part of an argument, the VM | |
| * may determine that the reference on the stack is no | |
| * longer reachable after marshalling (see 6181943)-- | |
| * therefore, tell the stream to save a reference until a | |
| * timeout expires or, for results, a DGCAck message has | |
| * been received from the caller, or for arguments, the | |
| * remote call has completed. For a "local" LiveRef, save | |
| * a reference to the impl directly, because the impl is | |
| * not reachable from the LiveRef (see 4114579); | |
| * otherwise, save a reference to the LiveRef, for the | |
| * client-side DGC to watch over. (Also see 4017232.) | |
| */ | |
| if (isLocal) { | |
| ObjectEndpoint oe = | |
| new ObjectEndpoint(id, ep.getInboundTransport()); | |
| Target target = ObjectTable.getTarget(oe); | |
| if (target != null) { | |
| Remote impl = target.getImpl(); | |
| if (impl != null) { | |
| stream.saveObject(impl); | |
| } | |
| } | |
| } else { | |
| stream.saveObject(this); | |
| } | |
| } | |
| // All together now write out the endpoint, id, and flag | |
| // (need to choose whether or not to use old JDK1.1 endpoint format) | |
| if (useNewFormat) { | |
| ((TCPEndpoint) ep).write(out); | |
| } else { | |
| ((TCPEndpoint) ep).writeHostPortFormat(out); | |
| } | |
| id.write(out); | |
| out.writeBoolean(isResultStream); | |
| } | |
| public static LiveRef read(ObjectInput in, boolean useNewFormat) | |
| throws IOException, ClassNotFoundException | |
| { | |
| Endpoint ep; | |
| ObjID id; | |
| // Now read in the endpoint, id, and result flag | |
| // (need to choose whether or not to read old JDK1.1 endpoint format) | |
| if (useNewFormat) { | |
| ep = TCPEndpoint.read(in); | |
| } else { | |
| ep = TCPEndpoint.readHostPortFormat(in); | |
| } | |
| id = ObjID.read(in); | |
| boolean isResultStream = in.readBoolean(); | |
| LiveRef ref = new LiveRef(id, ep, false); | |
| if (in instanceof ConnectionInputStream) { | |
| ConnectionInputStream stream = (ConnectionInputStream)in; | |
| // save ref to send "dirty" call after all args/returns | |
| // have been unmarshaled. | |
| stream.saveRef(ref); | |
| if (isResultStream) { | |
| // set flag in stream indicating that remote objects were | |
| // unmarshaled. A DGC ack should be sent by the transport. | |
| stream.setAckNeeded(); | |
| } | |
| } else { | |
| DGCClient.registerRefs(ep, Arrays.asList(new LiveRef[] { ref })); | |
| } | |
| return ref; | |
| } | |
| } |