1/* 2 * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.rmi.transport; 27 28import java.io.IOException; 29import java.io.ObjectOutput; 30import java.rmi.MarshalException; 31import java.rmi.NoSuchObjectException; 32import java.rmi.Remote; 33import java.rmi.RemoteException; 34import java.rmi.server.LogStream; 35import java.rmi.server.ObjID; 36import java.rmi.server.RemoteCall; 37import java.rmi.server.RemoteServer; 38import java.rmi.server.ServerNotActiveException; 39import java.security.AccessControlContext; 40import java.security.AccessController; 41import java.security.Permissions; 42import java.security.PrivilegedAction; 43import java.security.ProtectionDomain; 44import sun.rmi.runtime.Log; 45import sun.rmi.server.Dispatcher; 46import sun.rmi.server.UnicastServerRef; 47 48/** 49 * Transport abstraction for enabling communication between different 50 * VMs. 51 * 52 * @author Ann Wollrath 53 */ 54@SuppressWarnings("deprecation") 55public abstract class Transport { 56 57 /** "transport" package log level */ 58 static final int logLevel = LogStream.parseLevel(getLogLevel()); 59 60 private static String getLogLevel() { 61 return java.security.AccessController.doPrivileged( 62 (PrivilegedAction<String>) () -> System.getProperty("sun.rmi.transport.logLevel")); 63 } 64 65 /* transport package log */ 66 static final Log transportLog = 67 Log.getLog("sun.rmi.transport.misc", "transport", Transport.logLevel); 68 69 /** References the current transport when a call is being serviced */ 70 private static final ThreadLocal<Transport> currentTransport = new ThreadLocal<>(); 71 72 /** ObjID for DGCImpl */ 73 private static final ObjID dgcID = new ObjID(ObjID.DGC_ID); 74 75 /** AccessControlContext for setting context ClassLoader */ 76 private static final AccessControlContext SETCCL_ACC; 77 static { 78 Permissions perms = new Permissions(); 79 perms.add(new RuntimePermission("setContextClassLoader")); 80 ProtectionDomain[] pd = { new ProtectionDomain(null, perms) }; 81 SETCCL_ACC = new AccessControlContext(pd); 82 } 83 84 /** 85 * Returns a <I>Channel</I> that generates connections to the 86 * endpoint <I>ep</I>. A Channel is an object that creates and 87 * manages connections of a particular type to some particular 88 * address space. 89 * @param ep the endpoint to which connections will be generated. 90 * @return the channel or null if the transport cannot 91 * generate connections to this endpoint 92 */ 93 public abstract Channel getChannel(Endpoint ep); 94 95 /** 96 * Removes the <I>Channel</I> that generates connections to the 97 * endpoint <I>ep</I>. 98 */ 99 public abstract void free(Endpoint ep); 100 101 /** 102 * Export the object so that it can accept incoming calls. 103 */ 104 public void exportObject(Target target) throws RemoteException { 105 target.setExportedTransport(this); 106 ObjectTable.putTarget(target); 107 } 108 109 /** 110 * Invoked when an object that was exported on this transport has 111 * become unexported, either by being garbage collected or by 112 * being explicitly unexported. 113 **/ 114 protected void targetUnexported() { } 115 116 /** 117 * Returns the current transport if a call is being serviced, otherwise 118 * returns null. 119 **/ 120 static Transport currentTransport() { 121 return currentTransport.get(); 122 } 123 124 /** 125 * Verify that the current access control context has permission to accept 126 * the connection being dispatched by the current thread. The current 127 * access control context is passed as a parameter to avoid the overhead of 128 * an additional call to AccessController.getContext. 129 */ 130 protected abstract void checkAcceptPermission(AccessControlContext acc); 131 132 /** 133 * Sets the context class loader for the current thread. 134 */ 135 private static void setContextClassLoader(ClassLoader ccl) { 136 AccessController.doPrivileged((PrivilegedAction<Void>)() -> { 137 Thread.currentThread().setContextClassLoader(ccl); 138 return null; 139 }, SETCCL_ACC); 140 } 141 142 /** 143 * Service an incoming remote call. When a message arrives on the 144 * connection indicating the beginning of a remote call, the 145 * threads are required to call the <I>serviceCall</I> method of 146 * their transport. The default implementation of this method 147 * locates and calls the dispatcher object. Ordinarily a 148 * transport implementation will not need to override this method. 149 * At the entry to <I>tr.serviceCall(conn)</I>, the connection's 150 * input stream is positioned at the start of the incoming 151 * message. The <I>serviceCall</I> method processes the incoming 152 * remote invocation and sends the result on the connection's 153 * output stream. If it returns "true", then the remote 154 * invocation was processed without error and the transport can 155 * cache the connection. If it returns "false", a protocol error 156 * occurred during the call, and the transport should destroy the 157 * connection. 158 */ 159 public boolean serviceCall(final RemoteCall call) { 160 try { 161 /* read object id */ 162 final Remote impl; 163 ObjID id; 164 165 try { 166 id = ObjID.read(call.getInputStream()); 167 } catch (java.io.IOException e) { 168 throw new MarshalException("unable to read objID", e); 169 } 170 171 /* get the remote object */ 172 Transport transport = id.equals(dgcID) ? null : this; 173 Target target = 174 ObjectTable.getTarget(new ObjectEndpoint(id, transport)); 175 176 if (target == null || (impl = target.getImpl()) == null) { 177 throw new NoSuchObjectException("no such object in table"); 178 } 179 180 final Dispatcher disp = target.getDispatcher(); 181 target.incrementCallCount(); 182 try { 183 /* call the dispatcher */ 184 transportLog.log(Log.VERBOSE, "call dispatcher"); 185 186 final AccessControlContext acc = 187 target.getAccessControlContext(); 188 ClassLoader ccl = target.getContextClassLoader(); 189 190 ClassLoader savedCcl = Thread.currentThread().getContextClassLoader(); 191 192 try { 193 setContextClassLoader(ccl); 194 currentTransport.set(this); 195 try { 196 java.security.AccessController.doPrivileged( 197 new java.security.PrivilegedExceptionAction<Void>() { 198 public Void run() throws IOException { 199 checkAcceptPermission(acc); 200 disp.dispatch(impl, call); 201 return null; 202 } 203 }, acc); 204 } catch (java.security.PrivilegedActionException pae) { 205 throw (IOException) pae.getException(); 206 } 207 } finally { 208 setContextClassLoader(savedCcl); 209 currentTransport.set(null); 210 } 211 212 } catch (IOException ex) { 213 transportLog.log(Log.BRIEF, 214 "exception thrown by dispatcher: ", ex); 215 return false; 216 } finally { 217 target.decrementCallCount(); 218 } 219 220 } catch (RemoteException e) { 221 222 // if calls are being logged, write out exception 223 if (UnicastServerRef.callLog.isLoggable(Log.BRIEF)) { 224 // include client host name if possible 225 String clientHost = ""; 226 try { 227 clientHost = "[" + 228 RemoteServer.getClientHost() + "] "; 229 } catch (ServerNotActiveException ex) { 230 } 231 String message = clientHost + "exception: "; 232 UnicastServerRef.callLog.log(Log.BRIEF, message, e); 233 } 234 235 /* We will get a RemoteException if either a) the objID is 236 * not readable, b) the target is not in the object table, or 237 * c) the object is in the midst of being unexported (note: 238 * NoSuchObjectException is thrown by the incrementCallCount 239 * method if the object is being unexported). Here it is 240 * relatively safe to marshal an exception to the client 241 * since the client will not have seen a return value yet. 242 */ 243 try { 244 ObjectOutput out = call.getResultStream(false); 245 UnicastServerRef.clearStackTraces(e); 246 out.writeObject(e); 247 call.releaseOutputStream(); 248 249 } catch (IOException ie) { 250 transportLog.log(Log.BRIEF, 251 "exception thrown marshalling exception: ", ie); 252 return false; 253 } 254 } 255 256 return true; 257 } 258} 259