001: /*
002: * Copyright 1996-2001 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.rmi.transport.tcp;
027:
028: import java.io.*;
029: import java.net.InetAddress;
030: import java.net.Socket;
031: import java.net.SocketException;
032: import java.rmi.*;
033: import java.rmi.server.RMISocketFactory;
034: import sun.rmi.runtime.Log;
035: import sun.rmi.transport.*;
036: import sun.rmi.transport.proxy.*;
037:
038: public class TCPConnection implements Connection {
039:
040: private Socket socket;
041: private Channel channel;
042: private InputStream in = null;
043: private OutputStream out = null;
044: private long expiration = Long.MAX_VALUE;
045: private long lastuse = Long.MIN_VALUE;
046: private long roundtrip = 5; // round-trip time for ping
047:
048: /**
049: * Constructor used for creating a connection to accept call
050: * (an input connection)
051: */
052: TCPConnection(TCPChannel ch, Socket s, InputStream in,
053: OutputStream out) {
054: socket = s;
055: channel = ch;
056: this .in = in;
057: this .out = out;
058: }
059:
060: /**
061: * Constructor used by subclass when underlying input and output streams
062: * are already available.
063: */
064: TCPConnection(TCPChannel ch, InputStream in, OutputStream out) {
065: this (ch, null, in, out);
066: }
067:
068: /**
069: * Constructor used when socket is available, but not underlying
070: * streams.
071: */
072: TCPConnection(TCPChannel ch, Socket s) {
073: this (ch, s, null, null);
074: }
075:
076: /**
077: * Gets the output stream for this connection
078: */
079: public OutputStream getOutputStream() throws IOException {
080: if (out == null)
081: out = new BufferedOutputStream(socket.getOutputStream());
082: return out;
083: }
084:
085: /**
086: * Release the output stream for this connection.
087: */
088: public void releaseOutputStream() throws IOException {
089: if (out != null)
090: out.flush();
091: }
092:
093: /**
094: * Gets the input stream for this connection.
095: */
096: public InputStream getInputStream() throws IOException {
097: if (in == null)
098: in = new BufferedInputStream(socket.getInputStream());
099: return in;
100: }
101:
102: /**
103: * Release the input stream for this connection.
104: */
105: public void releaseInputStream() {
106: }
107:
108: /**
109: * Determine if this connection can be used for multiple operations.
110: * If the socket implements RMISocketInfo, then we can query it about
111: * this; otherwise, assume that it does provide a full-duplex
112: * persistent connection like java.net.Socket.
113: */
114: public boolean isReusable() {
115: if ((socket != null) && (socket instanceof RMISocketInfo))
116: return ((RMISocketInfo) socket).isReusable();
117: else
118: return true;
119: }
120:
121: /**
122: * Set the expiration time of this connection.
123: * @param time The time at which the time out expires.
124: */
125: void setExpiration(long time) {
126: expiration = time;
127: }
128:
129: /**
130: * Set the timestamp at which this connection was last used successfully.
131: * The connection will be pinged for liveness if reused long after
132: * this time.
133: * @param time The time at which the connection was last active.
134: */
135: void setLastUseTime(long time) {
136: lastuse = time;
137: }
138:
139: /**
140: * Returns true if the timeout has expired on this connection;
141: * otherwise returns false.
142: * @param time The current time.
143: */
144: boolean expired(long time) {
145: return expiration <= time;
146: }
147:
148: /**
149: * Probes the connection to see if it still alive and connected to
150: * a responsive server. If the connection has been idle for too
151: * long, the server is pinged. ``Too long'' means ``longer than the
152: * last ping round-trip time''.
153: * <P>
154: * This method may misdiagnose a dead connection as live, but it
155: * will never misdiagnose a live connection as dead.
156: * @return true if the connection and server are recently alive
157: */
158: public boolean isDead() {
159: InputStream i;
160: OutputStream o;
161:
162: // skip ping if recently used within 1 RTT
163: long start = System.currentTimeMillis();
164: if ((roundtrip > 0) && (start < lastuse + roundtrip))
165: return (false); // still alive and warm
166:
167: // Get the streams
168: try {
169: i = getInputStream();
170: o = getOutputStream();
171: } catch (IOException e) {
172: return (true); // can't even get a stream, must be very dead
173: }
174:
175: // Write the ping byte and read the reply byte
176: int response = 0;
177: try {
178: o.write(TransportConstants.Ping);
179: o.flush();
180: response = i.read();
181: } catch (IOException ex) {
182: TCPTransport.tcpLog.log(Log.VERBOSE, "exception: ", ex);
183: TCPTransport.tcpLog.log(Log.BRIEF, "server ping failed");
184:
185: return (true); // server failed the ping test
186: }
187:
188: if (response == TransportConstants.PingAck) {
189: // save most recent RTT for future use
190: roundtrip = (System.currentTimeMillis() - start) * 2;
191: // clock-correction may make roundtrip < 0; doesn't matter
192: return (false); // it's alive and 5-by-5
193: }
194:
195: if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) {
196: TCPTransport.tcpLog.log(Log.BRIEF,
197: (response == -1 ? "server has been deactivated"
198: : "server protocol error: ping response = "
199: + response));
200: }
201: return (true);
202: }
203:
204: /**
205: * Close the connection. */
206: public void close() throws IOException {
207: TCPTransport.tcpLog.log(Log.BRIEF, "close connection");
208:
209: if (socket != null)
210: socket.close();
211: else {
212: in.close();
213: out.close();
214: }
215: }
216:
217: /**
218: * Returns the channel for this connection.
219: */
220: public Channel getChannel() {
221: return channel;
222: }
223: }
|