/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* TCPTransport is the socket-based implementation of the RMI Transport
* abstraction.
*
* @author Ann Wollrath
* @author Peter Jones
*/
/* tcp package log */
new GetPropertyAction("sun.rmi.transport.tcp.logLevel"))));
/** maximum number of connection handler threads */
new GetIntegerAction("sun.rmi.transport.tcp.maxConnectionThreads",
/** keep alive time for idle connection handler threads */
new GetLongAction("sun.rmi.transport.tcp.threadKeepAliveTime",
60000));
/** thread pool for connection handlers */
new SynchronousQueue<Runnable>(),
new ThreadFactory() {
runnable, "TCP Connection(idle)", true, true));
}
});
/** total connections handled */
/** client host for the current thread's connection */
private static final ThreadLocal<ConnectionHandler>
/** endpoints for this transport */
/** number of objects exported on this transport */
/** server socket for this transport */
/** table mapping endpoints to channels */
new WeakHashMap<>();
/** number of milliseconds in accepted-connection timeout.
* Warning: this should be greater than 15 seconds (the client-side
* timeout), and defaults to 2 hours.
* The maximum representable value is slightly more than 24 days
* and 20 hours.
*/
new GetIntegerAction("sun.rmi.transport.tcp.readTimeout",
2 * 3600 * 1000));
/**
* Constructs a TCPTransport.
*/
// assert ((epList.size() != null) && (epList.size() >= 1))
}
}
/**
* Closes all cached connections in every channel subordinated to this
* transport. Currently, this only closes outgoing connections.
*/
public void shedConnectionCaches() {
synchronized (channelTable) {
}
}
}
}
}
/**
* Returns a <I>Channel</I> that generates connections to the
* endpoint <I>ep</I>. A Channel is an object that creates and
* manages connections of a particular type to some particular
* address space.
* @param ep the endpoint to which connections will be generated.
* @return the channel or null if the transport cannot
* generate connections to this endpoint
*/
if (ep instanceof TCPEndpoint) {
synchronized (channelTable) {
}
}
}
}
return ch;
}
/**
* Removes the <I>Channel</I> that generates connections to the
* endpoint <I>ep</I>.
*/
if (ep instanceof TCPEndpoint) {
synchronized (channelTable) {
}
}
}
}
}
/**
* Export the object so that it can accept incoming calls.
*/
/*
* Ensure that a server socket is listening, and count this
* export while synchronized to prevent the server socket from
* being closed due to concurrent unexports.
*/
synchronized (this) {
listen();
exportCount++;
}
/*
* Try to add the Target to the exported object table; keep
* counting this export (to keep server socket open) only if
* that succeeds.
*/
boolean ok = false;
try {
super.exportObject(target);
ok = true;
} finally {
if (!ok) {
synchronized (this) {
}
}
}
}
protected synchronized void targetUnexported() {
}
/**
* Decrements the count of exported objects, closing the current
* server socket if the count reaches zero.
**/
private void decrementExportCount() {
exportCount--;
try {
} catch (IOException e) {
}
}
}
/**
* Verify that the current access control context has permission to
* accept the connection being dispatched by the current thread.
*/
return;
}
if (h == null) {
throw new Error(
"checkAcceptPermission not in ConnectionHandler thread");
}
}
synchronized (epList) {
}
}
/**
* Listen on transport's endpoint.
*/
}
try {
/*
* Don't retry ServerSocket if creation fails since
* "port in use" will cause export to hang if an
* RMIFailureHandler is not installed.
*/
"TCP Accept-" + port, true));
t.start();
} catch (IOException e) {
}
} else {
// otherwise verify security access to existing server socket
}
}
}
/**
* Worker for accepting connections from a server socket.
**/
// state for throttling loop on exceptions (local to accept thread)
private int recentExceptionCount;
this.serverSocket = serverSocket;
}
public void run() {
try {
} finally {
try {
/*
* Only one accept loop is started per server
* socket, so after no more connections will be
* accepted, ensure that the server socket is no
* longer listening.
*/
} catch (IOException e) {
}
}
}
/**
* Accepts connections from the server socket and executes
* handlers for them in the thread pool.
**/
private void executeAcceptLoop() {
getEndpoint().getPort());
}
while (true) {
try {
/*
* Find client host name (or "0.0.0.0" if unknown)
*/
: "0.0.0.0");
/*
* Execute connection handler in the thread pool,
* which uses non-system threads.
*/
try {
} catch (RejectedExecutionException e) {
"rejected connection from " + clientHost);
}
} catch (Throwable t) {
try {
/*
* If the server socket has been closed, such
* as because there are no more exported
* objects, then we expect accept to throw an
* exception, so just terminate normally.
*/
if (serverSocket.isClosed()) {
break;
}
try {
"accept loop for " + serverSocket +
" throws", t);
}
}
} finally {
/*
* Always close the accepted socket (if any)
* if an exception occurs, but only after
* logging an unexpected exception.
*/
}
}
/*
* In case we're running out of file descriptors,
* release resources held in caches.
*/
if (!(t instanceof SecurityException)) {
try {
}
}
/*
* A NoClassDefFoundError can occur if no file
* descriptors are available, in which case this
* loop should not terminate.
*/
if (t instanceof Exception ||
t instanceof OutOfMemoryError ||
t instanceof NoClassDefFoundError)
{
if (!continueAfterAcceptFailure(t)) {
return;
}
// continue loop
} else if (t instanceof Error) {
throw (Error) t;
} else {
throw new UndeclaredThrowableException(t);
}
}
}
}
/**
* Returns true if the accept loop should continue after the
* specified exception has been caught, or false if the accept
* loop should terminate (closing the server socket). If
* there is an RMIFailureHandler, this method returns the
* result of passing the specified exception to it; otherwise,
* this method always returns true, after sleeping to throttle
* the accept loop if necessary.
**/
new InvocationTargetException(t));
} else {
return true;
}
}
/**
* Throttles the accept loop after an exception has been
* caught: if a burst of 10 exceptions in 5 seconds occurs,
* then wait for 10 seconds to curb busy CPU usage.
**/
private void throttleLoopOnException() {
// last exception was long ago (or this is the first)
recentExceptionCount = 0;
} else {
// exception burst window was started recently
if (++recentExceptionCount >= 10) {
try {
} catch (InterruptedException ignore) {
}
}
}
}
}
/** close socket and eat exception */
try {
} catch (IOException ex) {
// eat exception
}
}
/**
* handleMessages decodes transport operations and handles messages
* appropriately. If an exception occurs during message handling,
* the socket is closed.
*/
try {
do {
if (op == -1) {
port + ") connection closed");
}
break;
}
") op = " + op);
}
switch (op) {
case TransportConstants.Call:
// service incoming RMI call
if (serviceCall(call) == false)
return;
break;
case TransportConstants.Ping:
// send ack for ping
break;
case TransportConstants.DGCAck:
break;
default:
}
} while (persistent);
} catch (IOException e) {
// exception during processing causes connection to close (below)
") exception: ", e);
}
} finally {
try {
} catch (IOException ex) {
// eat exception
}
}
}
/**
* Returns the client host for the current thread's connection. Throws
* ServerNotActiveException if no connection is active for this thread.
*/
if (h != null) {
return h.getClientHost();
} else {
throw new ServerNotActiveException("not in a remote call");
}
}
/**
* Services messages on accepted connection
*/
/** int value of "POST" in ASCII (Java's specified data formats
* make this once-reviled tactic again socially acceptable) */
/** most recently accept-authorized AccessControlContext */
/** cache of accept-authorized AccessControlContexts */
private Map<AccessControlContext,
/** security manager which authorized contexts in authCache */
this.remoteHost = remoteHost;
}
return remoteHost;
}
/**
* Verify that the given AccessControlContext has permission to
* accept this connection.
*/
{
/*
* Note: no need to synchronize on cache-related fields, since this
* method only gets called from the ConnectionHandler's thread.
*/
if (sm != cacheSecurityManager) {
}
return;
}
}
public void run() {
try {
t.setName("RMI TCP Connection(" +
")-" + remoteHost);
run0();
} finally {
}
}
private void run0() {
threadConnectionHandler.set(this);
// set socket to disable Nagle's algorithm (always send
// immediately)
// TBD: should this be left up to socket factory instead?
try {
socket.setTcpNoDelay(true);
} catch (Exception e) {
// if we fail to set this, ignore and proceed anyway
}
// set socket to timeout after excessive idle time
try {
if (connectionReadTimeout > 0)
} catch (Exception e) {
// too bad, continue anyway
}
try {
? sockIn
: new BufferedInputStream(sockIn);
// Read magic (or HTTP wrapper)
// It's really a HTTP-wrapped request. Repackage
// the socket in a HttpReceiveSocket, reinitialize
// sockIn and in, and reread magic.
try {
remoteHost = "0.0.0.0";
} catch (IOException e) {
throw new RemoteException("Error HTTP-unwrapping call",
e);
}
}
// bufIn's mark will invalidate itself when it overflows
// so it doesn't have to be turned off
// read and verify transport header
// protocol mismatch detected...
// just close socket: this would recurse if we marshal an
// exception to the client and the protocol at other end
// doesn't match.
return;
}
new BufferedOutputStream(sockOut);
}
// send ack (or nack) for protocol
switch (protocol) {
// no ack for protocol
// create dummy channel for receiving messages
// read input messages
handleMessages(conn, false);
break;
// send ack
// suggest endpoint (in case client doesn't know host name)
}
// read and discard (possibly bogus) endpoint
// REMIND: would be faster to read 2 bytes then skip N+4
}
// create dummy channel for receiving messages
// (why not use clientHost and clientPort?)
// read input messages
handleMessages(conn, true);
break;
") accepting multiplex protocol");
}
// send ack
// suggest endpoint (in case client doesn't already have one)
}
// read endpoint client has decided to use
port + ") client using " +
}
synchronized (channelTable) {
// create or find channel for this endpoint
false);
}
multiplexer.run();
break;
default:
// protocol not understood, send nack and close socket
break;
}
} catch (IOException e) {
// socket in unknown state: destroy socket
} finally {
}
}
}
}