1 /* 2 * Copyright (c) 1996, 2013, 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 26 package sun.rmi.transport; 27 28 import java.io.IOException; 29 import java.io.ObjectOutput; 30 import java.rmi.MarshalException; 31 import java.rmi.NoSuchObjectException; 32 import java.rmi.Remote; 33 import java.rmi.RemoteException; 34 import java.rmi.server.LogStream; 35 import java.rmi.server.ObjID; 36 import java.rmi.server.RemoteCall; 37 import java.rmi.server.RemoteServer; 38 import java.rmi.server.ServerNotActiveException; 39 import java.security.AccessControlContext; 40 import sun.rmi.runtime.Log; 41 import sun.rmi.server.Dispatcher; 42 import sun.rmi.server.UnicastServerRef; 43 44 /** 45 * Transport abstraction for enabling communication between different 46 * VMs. 47 * 48 * @author Ann Wollrath 49 */ 50 @SuppressWarnings("deprecation") 51 public abstract class Transport { 52 53 /** "transport" package log level */ 54 static final int logLevel = LogStream.parseLevel(getLogLevel()); 55 56 private static String getLogLevel() { 57 return java.security.AccessController.doPrivileged( 58 new sun.security.action.GetPropertyAction("sun.rmi.transport.logLevel")); 59 } 60 61 /* transport package log */ 62 static final Log transportLog = 63 Log.getLog("sun.rmi.transport.misc", "transport", Transport.logLevel); 64 65 /** References the current transport when a call is being serviced */ 66 private static final ThreadLocal<Transport> currentTransport = new ThreadLocal<>(); 67 68 /** ObjID for DGCImpl */ 69 private static final ObjID dgcID = new ObjID(ObjID.DGC_ID); 70 71 /** 72 * Returns a <I>Channel</I> that generates connections to the 73 * endpoint <I>ep</I>. A Channel is an object that creates and 74 * manages connections of a particular type to some particular 75 * address space. 76 * @param ep the endpoint to which connections will be generated. 77 * @return the channel or null if the transport cannot 78 * generate connections to this endpoint 79 */ 80 public abstract Channel getChannel(Endpoint ep); 81 82 /** 83 * Removes the <I>Channel</I> that generates connections to the 84 * endpoint <I>ep</I>. 85 */ 86 public abstract void free(Endpoint ep); 87 88 /** 89 * Export the object so that it can accept incoming calls. 90 */ 91 public void exportObject(Target target) throws RemoteException { 92 target.setExportedTransport(this); 93 ObjectTable.putTarget(target); 94 } 95 96 /** 97 * Invoked when an object that was exported on this transport has 98 * become unexported, either by being garbage collected or by 99 * being explicitly unexported. 100 **/ 101 protected void targetUnexported() { } 102 103 /** 104 * Returns the current transport if a call is being serviced, otherwise 105 * returns null. 106 **/ 107 static Transport currentTransport() { 108 return currentTransport.get(); 109 } 110 111 /** 112 * Verify that the current access control context has permission to accept 113 * the connection being dispatched by the current thread. The current 114 * access control context is passed as a parameter to avoid the overhead of 115 * an additional call to AccessController.getContext. 116 */ 117 protected abstract void checkAcceptPermission(AccessControlContext acc); 118 119 /** 120 * Service an incoming remote call. When a message arrives on the 121 * connection indicating the beginning of a remote call, the 122 * threads are required to call the <I>serviceCall</I> method of 123 * their transport. The default implementation of this method 124 * locates and calls the dispatcher object. Ordinarily a 125 * transport implementation will not need to override this method. 126 * At the entry to <I>tr.serviceCall(conn)</I>, the connection's 127 * input stream is positioned at the start of the incoming 128 * message. The <I>serviceCall</I> method processes the incoming 129 * remote invocation and sends the result on the connection's 130 * output stream. If it returns "true", then the remote 131 * invocation was processed without error and the transport can 132 * cache the connection. If it returns "false", a protocol error 133 * occurred during the call, and the transport should destroy the 134 * connection. 135 */ 136 public boolean serviceCall(final RemoteCall call) { 137 try { 138 /* read object id */ 139 final Remote impl; 140 ObjID id; 141 142 try { 143 id = ObjID.read(call.getInputStream()); 144 } catch (java.io.IOException e) { 145 throw new MarshalException("unable to read objID", e); 146 } 147 148 /* get the remote object */ 149 Transport transport = id.equals(dgcID) ? null : this; 150 Target target = 151 ObjectTable.getTarget(new ObjectEndpoint(id, transport)); 152 153 if (target == null || (impl = target.getImpl()) == null) { 154 throw new NoSuchObjectException("no such object in table"); 155 } 156 157 final Dispatcher disp = target.getDispatcher(); 158 target.incrementCallCount(); 159 try { 160 /* call the dispatcher */ 161 transportLog.log(Log.VERBOSE, "call dispatcher"); 162 163 final AccessControlContext acc = 164 target.getAccessControlContext(); 165 ClassLoader ccl = target.getContextClassLoader(); 166 167 Thread t = Thread.currentThread(); 168 ClassLoader savedCcl = t.getContextClassLoader(); 169 170 try { 171 t.setContextClassLoader(ccl); 172 currentTransport.set(this); 173 try { 174 java.security.AccessController.doPrivileged( 175 new java.security.PrivilegedExceptionAction<Void>() { 176 public Void run() throws IOException { 177 checkAcceptPermission(acc); 178 disp.dispatch(impl, call); 179 return null; 180 } 181 }, acc); 182 } catch (java.security.PrivilegedActionException pae) { 183 throw (IOException) pae.getException(); 184 } 185 } finally { 186 t.setContextClassLoader(savedCcl); 187 currentTransport.set(null); 188 } 189 190 } catch (IOException ex) { 191 transportLog.log(Log.BRIEF, 192 "exception thrown by dispatcher: ", ex); 193 return false; 194 } finally { 195 target.decrementCallCount(); 196 } 197 198 } catch (RemoteException e) { 199 200 // if calls are being logged, write out exception 201 if (UnicastServerRef.callLog.isLoggable(Log.BRIEF)) { 202 // include client host name if possible 203 String clientHost = ""; 204 try { 205 clientHost = "[" + 206 RemoteServer.getClientHost() + "] "; 207 } catch (ServerNotActiveException ex) { 208 } 209 String message = clientHost + "exception: "; 210 UnicastServerRef.callLog.log(Log.BRIEF, message, e); 211 } 212 213 /* We will get a RemoteException if either a) the objID is 214 * not readable, b) the target is not in the object table, or 215 * c) the object is in the midst of being unexported (note: 216 * NoSuchObjectException is thrown by the incrementCallCount 217 * method if the object is being unexported). Here it is 218 * relatively safe to marshal an exception to the client 219 * since the client will not have seen a return value yet. 220 */ 221 try { 222 ObjectOutput out = call.getResultStream(false); 223 UnicastServerRef.clearStackTraces(e); 224 out.writeObject(e); 225 call.releaseOutputStream(); 226 227 } catch (IOException ie) { 228 transportLog.log(Log.BRIEF, 229 "exception thrown marshalling exception: ", ie); 230 return false; 231 } 232 } 233 234 return true; 235 } 236 }