Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/rmi/transport/StreamRemoteCall.java
38831 views
/*1* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.rmi.transport;2627import java.io.DataInputStream;28import java.io.DataOutputStream;29import java.io.IOException;30import java.io.ObjectInput;31import java.io.ObjectOutput;32import java.io.StreamCorruptedException;33import java.rmi.RemoteException;34import java.rmi.MarshalException;35import java.rmi.UnmarshalException;36import java.rmi.server.ObjID;37import java.rmi.server.RemoteCall;38import java.security.AccessController;39import java.security.PrivilegedAction;4041import sun.misc.ObjectInputFilter;42import sun.rmi.runtime.Log;43import sun.rmi.server.UnicastRef;44import sun.rmi.transport.tcp.TCPEndpoint;4546/**47* Stream-based implementation of the RemoteCall interface.48*49* @author Ann Wollrath50*/51@SuppressWarnings("deprecation")52public class StreamRemoteCall implements RemoteCall {53private ConnectionInputStream in = null;54private ConnectionOutputStream out = null;55private Connection conn;56private ObjectInputFilter filter = null;57private boolean resultStarted = false;58private Exception serverException = null;5960public StreamRemoteCall(Connection c) {61conn = c;62}6364public StreamRemoteCall(Connection c, ObjID id, int op, long hash)65throws RemoteException66{67try {68conn = c;69Transport.transportLog.log(Log.VERBOSE,70"write remote call header...");7172// write out remote call header info...73// call header, part 1 (read by Transport)74conn.getOutputStream().write(TransportConstants.Call);75getOutputStream(); // creates a MarshalOutputStream76id.write(out); // object id (target of call)77// call header, part 2 (read by Dispatcher)78out.writeInt(op); // method number (operation index)79out.writeLong(hash); // stub/skeleton hash80} catch (IOException e) {81throw new MarshalException("Error marshaling call header", e);82}83}8485/**86* Return the connection associated with this call.87*/88public Connection getConnection() {89return conn;90}9192/**93* Return the output stream the stub/skeleton should put arguments/results94* into.95*/96public ObjectOutput getOutputStream() throws IOException {97return getOutputStream(false);98}99100private ObjectOutput getOutputStream(boolean resultStream)101throws IOException102{103if (out == null) {104Transport.transportLog.log(Log.VERBOSE, "getting output stream");105106out = new ConnectionOutputStream(conn, resultStream);107}108return out;109}110111/**112* Release the outputStream Currently, will not complain if the113* output stream is released more than once.114*/115public void releaseOutputStream() throws IOException {116try {117if (out != null) {118try {119out.flush();120} finally {121out.done(); // always start DGC ack timer122}123}124conn.releaseOutputStream();125} finally {126out = null;127}128}129130public void setObjectInputFilter(ObjectInputFilter filter) {131if (in != null) {132throw new IllegalStateException("set filter must occur before calling getInputStream");133}134this.filter = filter;135}136137/**138* Get the InputStream the stub/skeleton should get results/arguments139* from.140*/141public ObjectInput getInputStream() throws IOException {142if (in == null) {143Transport.transportLog.log(Log.VERBOSE, "getting input stream");144145in = new ConnectionInputStream(conn.getInputStream());146if (filter != null) {147AccessController.doPrivileged((PrivilegedAction<Void>) () -> {148ObjectInputFilter.Config.setObjectInputFilter(in, filter);149return null;150});151}152}153return in;154}155156/**157* Release the input stream, this would allow some transports to release158* the channel early.159*/160public void releaseInputStream() throws IOException {161/* WARNING: Currently, the UnicastRef.java invoke methods rely162* upon this method not throwing an IOException.163*/164165try {166if (in != null) {167// execute MarshalInputStream "done" callbacks168try {169in.done();170} catch (RuntimeException e) {171}172173// add saved references to DGC table174in.registerRefs();175176/* WARNING: The connection being passed to done may have177* already been freed.178*/179in.done(conn);180}181conn.releaseInputStream();182} finally {183in = null;184}185}186187/**188* Discard any post-processing of refs the InputStream.189*/190public void discardPendingRefs() {191in.discardRefs();192}193194/**195* Returns an output stream (may put out header information196* relating to the success of the call).197* @param success If true, indicates normal return, else indicates198* exceptional return.199* @exception StreamCorruptedException If result stream previously200* acquired201* @exception IOException For any other problem with I/O.202*/203public ObjectOutput getResultStream(boolean success) throws IOException {204/* make sure result code only marshaled once. */205if (resultStarted)206throw new StreamCorruptedException("result already in progress");207else208resultStarted = true;209210// write out return header211// return header, part 1 (read by Transport)212DataOutputStream wr = new DataOutputStream(conn.getOutputStream());213wr.writeByte(TransportConstants.Return);// transport op214getOutputStream(true); // creates a MarshalOutputStream215// return header, part 2 (read by client-side RemoteCall)216if (success) //217out.writeByte(TransportConstants.NormalReturn);218else219out.writeByte(TransportConstants.ExceptionalReturn);220out.writeID(); // write id for gcAck221return out;222}223224/**225* Do whatever it takes to execute the call.226*/227@SuppressWarnings("fallthrough")228public void executeCall() throws Exception {229byte returnType;230231// read result header232DGCAckHandler ackHandler = null;233try {234if (out != null) {235ackHandler = out.getDGCAckHandler();236}237releaseOutputStream();238DataInputStream rd = new DataInputStream(conn.getInputStream());239byte op = rd.readByte();240if (op != TransportConstants.Return) {241if (Transport.transportLog.isLoggable(Log.BRIEF)) {242Transport.transportLog.log(Log.BRIEF,243"transport return code invalid: " + op);244}245throw new UnmarshalException("Transport return code invalid");246}247getInputStream();248returnType = in.readByte();249in.readID(); // id for DGC acknowledgement250} catch (UnmarshalException e) {251throw e;252} catch (IOException e) {253throw new UnmarshalException("Error unmarshaling return header",254e);255} finally {256if (ackHandler != null) {257ackHandler.release();258}259}260261// read return value262switch (returnType) {263case TransportConstants.NormalReturn:264break;265266case TransportConstants.ExceptionalReturn:267Object ex;268try {269ex = in.readObject();270} catch (Exception e) {271discardPendingRefs();272throw new UnmarshalException("Error unmarshaling return", e);273}274275// An exception should have been received,276// if so throw it, else flag error277if (ex instanceof Exception) {278exceptionReceivedFromServer((Exception) ex);279} else {280discardPendingRefs();281throw new UnmarshalException("Return type not Exception");282}283// Exception is thrown before fallthrough can occur284default:285if (Transport.transportLog.isLoggable(Log.BRIEF)) {286Transport.transportLog.log(Log.BRIEF,287"return code invalid: " + returnType);288}289throw new UnmarshalException("Return code invalid");290}291}292293/**294* Routine that causes the stack traces of remote exceptions to be295* filled in with the current stack trace on the client. Detail296* exceptions are filled in iteratively.297*/298protected void exceptionReceivedFromServer(Exception ex) throws Exception {299serverException = ex;300301StackTraceElement[] serverTrace = ex.getStackTrace();302StackTraceElement[] clientTrace = (new Throwable()).getStackTrace();303StackTraceElement[] combinedTrace =304new StackTraceElement[serverTrace.length + clientTrace.length];305System.arraycopy(serverTrace, 0, combinedTrace, 0,306serverTrace.length);307System.arraycopy(clientTrace, 0, combinedTrace, serverTrace.length,308clientTrace.length);309ex.setStackTrace(combinedTrace);310311/*312* Log the details of a server exception thrown as a result of a313* remote method invocation.314*/315if (UnicastRef.clientCallLog.isLoggable(Log.BRIEF)) {316/* log call exception returned from server before it is rethrown */317TCPEndpoint ep = (TCPEndpoint) conn.getChannel().getEndpoint();318UnicastRef.clientCallLog.log(Log.BRIEF, "outbound call " +319"received exception: [" + ep.getHost() + ":" +320ep.getPort() + "] exception: ", ex);321}322323throw ex;324}325326/*327* method to retrieve possible server side exceptions (which will328* be throw from exceptionReceivedFromServer(...) )329*/330public Exception getServerException() {331return serverException;332}333334public void done() throws IOException {335/* WARNING: Currently, the UnicastRef.java invoke methods rely336* upon this method not throwing an IOException.337*/338339releaseInputStream();340}341}342343344