001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Mikhail A. Markov
021: * @version $Revision: 1.1.2.2 $
022: */package org.apache.harmony.rmi.transport.tcp;
023:
024: import java.io.DataInputStream;
025: import java.io.DataOutputStream;
026: import java.io.IOException;
027: import java.net.Socket;
028: import java.rmi.ConnectIOException;
029: import java.rmi.RemoteException;
030: import java.security.AccessController;
031:
032: import org.apache.harmony.rmi.client.ClientConnection;
033: import org.apache.harmony.rmi.client.ClientConnectionManager;
034: import org.apache.harmony.rmi.common.GetLongPropAction;
035: import org.apache.harmony.rmi.common.RMILog;
036: import org.apache.harmony.rmi.common.RMIProperties;
037: import org.apache.harmony.rmi.internal.nls.Messages;
038: import org.apache.harmony.rmi.transport.Endpoint;
039:
040: /**
041: * Direct socket connection.
042: *
043: * @author Mikhail A. Markov
044: * @version $Revision: 1.1.2.2 $
045: */
046: public class TcpConnection extends ClientConnection {
047:
048: // status of availability for remote calls
049: private boolean available;
050:
051: // lock object for synchronization
052: private class Lock {
053: }
054:
055: private Object lock = new Lock();
056:
057: // when this connection could be closed (if it's available)
058: private long expiration;
059:
060: /** Log for logging tcp connections activity. */
061: protected static final RMILog tcpTransportLog = RMILog
062: .getTcpTransportLog();
063:
064: /*
065: * The time which will be used as a socket read timeout when reading
066: * protocol acknowledgement data while establishing a new connection.
067: * The default value is 60000 ms (1 minute).
068: */
069: private static int handshakeTimeout = ((Long) AccessController
070: .doPrivileged(new GetLongPropAction(
071: RMIProperties.HANDSHAKETIMEOUT_PROP, 60000)))
072: .intValue();
073:
074: /**
075: * @see ClientConnection(Socket, Endpoint)
076: */
077: public TcpConnection(Socket s, Endpoint ep) throws RemoteException {
078: super (s, ep);
079: available = false;
080: }
081:
082: /**
083: * Acknowledge protocol with server side.
084: *
085: * @return acknowledged protocol number
086: *
087: * @throws RemoteException if any I/O exception occurred during protocol
088: * acknowledgement
089: */
090: protected int serverProtocolAck() throws RemoteException {
091: try {
092: DataOutputStream dout = new DataOutputStream(out);
093:
094: // write RMI header and protocol version
095: writeHeader(dout);
096:
097: // write protocol type
098: dout.writeByte(STREAM_PROTOCOL);
099: out.flush();
100:
101: if (tcpTransportLog.isLoggable(RMILog.VERBOSE)) {
102: // rmi.90=Using stream RMI protocol
103: tcpTransportLog.log(RMILog.VERBOSE, Messages
104: .getString("rmi.90")); //$NON-NLS-1$
105: }
106:
107: // set handshakeTimeout
108: int origTimeout = 0;
109:
110: try {
111: origTimeout = s.getSoTimeout();
112: s.setSoTimeout(handshakeTimeout);
113: } catch (Exception ex) {
114: }
115:
116: // read protocol acknowledgement
117: DataInputStream din = new DataInputStream(in);
118: int ack = din.readByte();
119:
120: if (ack != PROTOCOL_ACK) {
121: // rmi.log.137=Protocol version {0} is not supported.
122: // rmi.log.13C=Unknown protocol response: {0}
123: throw new ConnectIOException(
124: (ack == PROTOCOL_NOT_SUPPORTED) ? (Messages
125: .getString(
126: "rmi.log.137", STREAM_PROTOCOL)) //$NON-NLS-1$
127: : (Messages.getString(
128: "rmi.log.13C", ack))); //$NON-NLS-1$
129: }
130:
131: // read host and port
132: String host = din.readUTF();
133: int port = din.readInt();
134:
135: if (tcpTransportLog.isLoggable(RMILog.VERBOSE)) {
136: // rmi.log.138=Server is seeing us as {0}:{1}
137: tcpTransportLog.log(RMILog.VERBOSE, Messages.getString(
138: "rmi.log.138", host, port)); //$NON-NLS-1$
139: }
140:
141: // restore original value of soTimeout
142: try {
143: s.setSoTimeout(origTimeout);
144: } catch (Exception ex) {
145: }
146:
147: // send our host and port (for Stream protocol they'll be ignored)
148: dout.writeUTF(host);
149: dout.writeInt(port);
150: dout.flush();
151: } catch (RemoteException re) {
152: close();
153: throw re;
154: } catch (IOException ioe) {
155: close();
156: // rmi.92=Unable to acknowledge protocol with server
157: throw new ConnectIOException(
158: Messages.getString("rmi.92"), ioe); //$NON-NLS-1$
159: }
160:
161: // protocol is agreed
162: return STREAM_PROTOCOL;
163: }
164:
165: /**
166: * @see ClientConnection.done()
167: */
168: public void done() {
169: synchronized (lock) {
170: available = true;
171: expiration = System.currentTimeMillis()
172: + ClientConnectionManager.connTimeout;
173: }
174: }
175:
176: /**
177: * @see ClientConnection.reuse()
178: */
179: public synchronized boolean reuse() {
180: synchronized (lock) {
181: if (!available) {
182: return false;
183: }
184: }
185: int ackResp = 0;
186:
187: try {
188: out.write(PING_MSG);
189: out.flush();
190: ackResp = in.read();
191: } catch (IOException ioe) {
192: if (tcpTransportLog.isLoggable(RMILog.BRIEF)) {
193: // rmi.log.139=Ping request for {0} failed.
194: tcpTransportLog.log(RMILog.BRIEF, Messages.getString(
195: "rmi.log.139", toString())); //$NON-NLS-1$
196: }
197: close(false);
198: return false;
199: }
200:
201: if (ackResp != PING_ACK) {
202: if (tcpTransportLog.isLoggable(RMILog.BRIEF)) {
203: // rmi.log.13A=Unknown response to ping request for {0}:{1}
204: tcpTransportLog.log(RMILog.BRIEF, Messages.getString(
205: "rmi.log.13A", toString(), //$NON-NLS-1$
206: ackResp));
207: }
208: close(false);
209: return false;
210: }
211:
212: synchronized (lock) {
213: available = false;
214: }
215:
216: if (tcpTransportLog.isLoggable(RMILog.BRIEF)) {
217: // rmi.log.13B=Reusing {0}...
218: tcpTransportLog.log(RMILog.BRIEF, Messages.getString(
219: "rmi.log.13B", toString())); //$NON-NLS-1$
220: }
221: return true;
222: }
223:
224: /**
225: * @see ClientConnection.isAvailable()
226: */
227: public boolean isAvailable() {
228: synchronized (lock) {
229: return available;
230: }
231: }
232:
233: /**
234: * Returns true because this connection could be reused.
235: *
236: * @see ClientConnection.isReusable()
237: */
238: public boolean isReusable() {
239: return true;
240: }
241:
242: /**
243: * @see ClientConnection.getExpiration()
244: */
245: public long getExpiration() {
246: synchronized (lock) {
247: if (!available) {
248: return -1;
249: }
250: return expiration;
251: }
252: }
253: }
|