jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java
changeset 25859 3317bb8137f4
parent 5506 202f599c92aa
child 37666 71d351269690
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPConnection.java	Sun Aug 17 15:54:13 2014 +0100
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1996, 2001, 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.tcp;
+
+import java.io.*;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.rmi.*;
+import java.rmi.server.RMISocketFactory;
+import sun.rmi.runtime.Log;
+import sun.rmi.transport.*;
+import sun.rmi.transport.proxy.*;
+
+public class TCPConnection implements Connection {
+
+    private Socket socket;
+    private Channel channel;
+    private InputStream in = null;
+    private OutputStream out = null;
+    private long expiration = Long.MAX_VALUE;
+    private long lastuse = Long.MIN_VALUE;
+    private long roundtrip = 5; // round-trip time for ping
+
+    /**
+     * Constructor used for creating a connection to accept call
+     * (an input connection)
+     */
+    TCPConnection(TCPChannel ch, Socket s, InputStream in, OutputStream out)
+    {
+        socket   = s;
+        channel  = ch;
+        this.in  = in;
+        this.out = out;
+    }
+
+    /**
+     * Constructor used by subclass when underlying input and output streams
+     * are already available.
+     */
+    TCPConnection(TCPChannel ch, InputStream in, OutputStream out)
+    {
+        this(ch, null, in, out);
+    }
+
+    /**
+     * Constructor used when socket is available, but not underlying
+     * streams.
+     */
+    TCPConnection(TCPChannel ch, Socket s)
+    {
+        this(ch, s, null, null);
+    }
+
+    /**
+     * Gets the output stream for this connection
+     */
+    public OutputStream getOutputStream() throws IOException
+    {
+        if (out == null)
+            out = new BufferedOutputStream(socket.getOutputStream());
+        return out;
+    }
+
+    /**
+     * Release the output stream for this connection.
+     */
+    public void releaseOutputStream() throws IOException
+    {
+        if (out != null)
+            out.flush();
+    }
+
+    /**
+     * Gets the input stream for this connection.
+     */
+    public InputStream getInputStream() throws IOException
+    {
+        if (in == null)
+            in = new BufferedInputStream(socket.getInputStream());
+        return in;
+    }
+
+
+    /**
+     * Release the input stream for this connection.
+     */
+    public void releaseInputStream()
+    {
+    }
+
+    /**
+     * Determine if this connection can be used for multiple operations.
+     * If the socket implements RMISocketInfo, then we can query it about
+     * this; otherwise, assume that it does provide a full-duplex
+     * persistent connection like java.net.Socket.
+     */
+    public boolean isReusable()
+    {
+        if ((socket != null) && (socket instanceof RMISocketInfo))
+            return ((RMISocketInfo) socket).isReusable();
+        else
+            return true;
+    }
+
+    /**
+     * Set the expiration time of this connection.
+     * @param time The time at which the time out expires.
+     */
+    void setExpiration(long time)
+    {
+        expiration = time;
+    }
+
+    /**
+     * Set the timestamp at which this connection was last used successfully.
+     * The connection will be pinged for liveness if reused long after
+     * this time.
+     * @param time The time at which the connection was last active.
+     */
+    void setLastUseTime(long time)
+    {
+        lastuse = time;
+    }
+
+    /**
+     * Returns true if the timeout has expired on this connection;
+     * otherwise returns false.
+     * @param time The current time.
+     */
+    boolean expired(long time)
+    {
+        return expiration <= time;
+    }
+
+    /**
+     * Probes the connection to see if it still alive and connected to
+     * a responsive server.  If the connection has been idle for too
+     * long, the server is pinged.  ``Too long'' means ``longer than the
+     * last ping round-trip time''.
+     * <P>
+     * This method may misdiagnose a dead connection as live, but it
+     * will never misdiagnose a live connection as dead.
+     * @return true if the connection and server are recently alive
+     */
+    public boolean isDead()
+    {
+        InputStream i;
+        OutputStream o;
+
+        // skip ping if recently used within 1 RTT
+        long start = System.currentTimeMillis();
+        if ((roundtrip > 0) && (start < lastuse + roundtrip))
+            return (false);     // still alive and warm
+
+        // Get the streams
+        try {
+            i = getInputStream();
+            o = getOutputStream();
+        } catch (IOException e) {
+            return (true);      // can't even get a stream, must be very dead
+        }
+
+        // Write the ping byte and read the reply byte
+        int response = 0;
+        try {
+            o.write(TransportConstants.Ping);
+            o.flush();
+            response = i.read();
+        } catch (IOException ex) {
+            TCPTransport.tcpLog.log(Log.VERBOSE, "exception: ", ex);
+            TCPTransport.tcpLog.log(Log.BRIEF, "server ping failed");
+
+            return (true);      // server failed the ping test
+        }
+
+        if (response == TransportConstants.PingAck) {
+            // save most recent RTT for future use
+            roundtrip = (System.currentTimeMillis() - start) * 2;
+            // clock-correction may make roundtrip < 0; doesn't matter
+            return (false);     // it's alive and 5-by-5
+        }
+
+        if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) {
+            TCPTransport.tcpLog.log(Log.BRIEF,
+                (response == -1 ? "server has been deactivated" :
+                "server protocol error: ping response = " + response));
+        }
+        return (true);
+    }
+
+    /**
+     * Close the connection.  */
+    public void close() throws IOException
+    {
+        TCPTransport.tcpLog.log(Log.BRIEF, "close connection");
+
+        if (socket != null)
+            socket.close();
+        else {
+            in.close();
+            out.close();
+        }
+    }
+
+    /**
+     * Returns the channel for this connection.
+     */
+    public Channel getChannel()
+    {
+        return channel;
+    }
+}