• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18 
19 /**
20  * @author Ivan G. Popov
21  */
22 
23 /**
24  * Created on 05.23.2004
25  */
26 package org.apache.harmony.jpda.tests.framework.jdwp;
27 
28 
29 import java.net.InetAddress;
30 import java.net.ServerSocket;
31 import java.net.Socket;
32 import java.net.SocketTimeoutException;
33 import java.io.InputStream;
34 import java.io.InterruptedIOException;
35 import java.io.OutputStream;
36 import java.io.IOException;
37 
38 import org.apache.harmony.jpda.tests.framework.jdwp.Packet;
39 
40 /**
41  * This class provides TransportWrapper for row TCP/IP socket connection.
42  *
43  */
44 public class SocketTransportWrapper implements TransportWrapper {
45 
46     public static final String HANDSHAKE_STRING = "JDWP-Handshake";
47 
48     private ServerSocket serverSocket;
49     private Socket transportSocket;
50     private InputStream input;
51     private OutputStream output;
52 
53     /**
54      * Starts listening for connection on given or default address.
55      *
56      * @param address address to listen or null for default address
57      * @return string representation of listening address
58      */
startListening(String address)59     public String startListening(String address) throws IOException {
60         String hostName = null;
61         InetAddress hostAddr = null;
62         int port = 0;
63         if (address != null) {
64             String portName = null;
65             int i = address.indexOf(':');
66             if (i < 0) {
67                 portName = address;
68             } else {
69                 hostName = address.substring(0, i);
70                 portName = address.substring(i+1);
71             }
72             try {
73                 port = Integer.parseInt(portName);
74             } catch (NumberFormatException e) {
75                 throw new IOException("Illegal port number in socket address: " + address);
76             }
77         }
78 
79         if (hostName != null) {
80             hostAddr = InetAddress.getByName(hostName);
81             serverSocket = new ServerSocket(port, 0, hostAddr);
82         } else {
83             serverSocket = new ServerSocket(port);
84         }
85 
86         // use as workaround for unspecified behaviour of isAnyLocalAddress()
87         InetAddress iAddress = null;
88         if (hostName != null) {
89             iAddress = serverSocket.getInetAddress();
90         } else {
91             iAddress = InetAddress.getLocalHost();
92         }
93 
94         address = iAddress.getHostName() + ":" + serverSocket.getLocalPort();
95         return address;
96     }
97 
98     /**
99      * Stops listening for connection on current address.
100      */
stopListening()101     public void stopListening() throws IOException {
102         if (serverSocket != null) {
103             serverSocket.close();
104         }
105     }
106 
107     /**
108      * Accepts transport connection for currently listened address and performs handshaking
109      * for specified timeout.
110      *
111      * @param acceptTimeout timeout for accepting in milliseconds
112      * @param handshakeTimeout timeout for handshaking in milliseconds
113      */
accept(long acceptTimeout, long handshakeTimeout)114     public void accept(long acceptTimeout, long handshakeTimeout) throws IOException {
115         synchronized (serverSocket) {
116             serverSocket.setSoTimeout((int) acceptTimeout);
117             try {
118                 transportSocket = serverSocket.accept();
119             } finally {
120                 serverSocket.setSoTimeout(0);
121             }
122         }
123         createStreams();
124         handshake(handshakeTimeout);
125     }
126 
127     /**
128      * Attaches transport connection to given address and performs handshaking
129      * for specified timeout.
130      *
131      * @param address address for attaching
132      * @param attachTimeout timeout for attaching in milliseconds
133      * @param handshakeTimeout timeout for handshaking in milliseconds
134      */
attach(String address, long attachTimeout, long handshakeTimeout)135     public void attach(String address, long attachTimeout, long handshakeTimeout) throws IOException {
136         if (address == null) {
137             throw new IOException("Illegal socket address: " + address);
138         }
139 
140         String hostName = null;
141         int port = 0;
142         {
143             String portName = null;
144             int i = address.indexOf(':');
145             if (i < 0) {
146                 throw new IOException("Illegal socket address: " + address);
147             } else {
148                 hostName = address.substring(0, i);
149                 portName = address.substring(i+1);
150             }
151             try {
152                 port = Integer.parseInt(portName);
153             } catch (NumberFormatException e) {
154                 throw new IOException("Illegal port number in socket address: " + address);
155             }
156         }
157 
158         long finishTime = System.currentTimeMillis() + attachTimeout;
159         long sleepTime = 4 * 1000; // millesecinds
160         IOException exception = null;
161         try {
162             do {
163                 try {
164                     transportSocket = new Socket(hostName, port);
165                     break;
166                 } catch (IOException e) {
167                     Thread.sleep(sleepTime);
168                 }
169             } while (attachTimeout == 0 || System.currentTimeMillis() < finishTime);
170         } catch (InterruptedException e) {
171             throw new InterruptedIOException("Interruption in attaching to " + address);
172         }
173 
174         if (transportSocket == null) {
175             if (exception != null) {
176                 throw exception;
177             } else {
178                 throw new SocketTimeoutException("Timeout exceeded in attaching to " + address);
179             }
180         }
181 
182         createStreams();
183         handshake(handshakeTimeout);
184     }
185 
186     /**
187      * Closes transport connection.
188      */
close()189     public void close() throws IOException {
190         if (input != null) {
191             input.close();
192         }
193         if (output != null) {
194             output.close();
195         }
196 
197         if (transportSocket != null && input == null && output == null && !transportSocket.isClosed()) {
198             transportSocket.close();
199         }
200         if (serverSocket != null) {
201             serverSocket.close();
202         }
203     }
204 
205     /**
206      * Checks if transport connection is open.
207      *
208      * @return true if transport connection is open
209      */
isOpen()210     public boolean isOpen() {
211         return (transportSocket != null
212                     && transportSocket.isConnected()
213                     && !transportSocket.isClosed());
214     }
215 
216     /**
217      * Reads packet bytes from transport connection.
218      *
219      * @return packet as byte array or null or empty packet if connection was closed
220      */
readPacket()221     public byte[] readPacket() throws IOException {
222 
223         // read packet header
224         byte[] header = new byte[Packet.HEADER_SIZE];
225         int off = 0;
226 
227         while (off < Packet.HEADER_SIZE) {
228             try {
229                 int bytesRead = input.read(header, off, Packet.HEADER_SIZE - off);
230                 if (bytesRead < 0) {
231                     break;
232                 }
233                 off += bytesRead;
234             } catch (IOException e) {
235                 // workaround for "Socket Closed" exception if connection was closed
236                 break;
237             }
238         }
239 
240         if (off == 0) {
241             return null;
242         }
243         if (off < Packet.HEADER_SIZE) {
244             throw new IOException("Connection closed in reading packet header");
245         }
246 
247         // extract packet length
248         int len = Packet.getPacketLength(header);
249         if (len < Packet.HEADER_SIZE) {
250             throw new IOException("Wrong packet size detected: " + len);
251         }
252 
253         // allocate packet bytes and store header there
254         byte[] bytes = new byte[len];
255         System.arraycopy(header, 0, bytes, 0, Packet.HEADER_SIZE);
256 
257         // read packet data
258         while (off < len) {
259             int bytesRead = input.read(bytes, off, len - off);
260             if (bytesRead < 0) {
261                 break;
262             }
263             off += bytesRead;
264         }
265         if (off < len) {
266             throw new IOException("Connection closed in reading packet data");
267         }
268 
269         return bytes;
270     }
271 
272     /**
273      * Writes packet bytes to transport connection.
274      *
275      * @param packet
276      *            packet as byte array
277      */
writePacket(byte[] packet)278     public void writePacket(byte[] packet) throws IOException {
279         output.write(packet);
280         output.flush();
281     }
282 
283     /**
284      * Performs handshaking for given timeout.
285      *
286      * @param handshakeTimeout timeout for handshaking in milliseconds
287      */
handshake(long handshakeTimeout)288     protected void handshake(long handshakeTimeout) throws IOException {
289         transportSocket.setSoTimeout((int) handshakeTimeout);
290 
291         try {
292             output.write(HANDSHAKE_STRING.getBytes());
293             output.flush();
294             int len = HANDSHAKE_STRING.length();
295             byte[] bytes = new byte[len];
296             int off = 0;
297             while (off < len) {
298                 int bytesRead = input.read(bytes, off, len - off);
299                 if (bytesRead < 0) {
300                     break;
301                 }
302                 off += bytesRead;
303             }
304             String response = new String(bytes, 0, off);
305             if (!response.equals(HANDSHAKE_STRING)) {
306                 throw new IOException("Unexpected handshake response: " + response);
307             }
308         } finally {
309             transportSocket.setSoTimeout(0);
310         }
311     }
312 
313     /**
314      * Creates input/output streams for connection socket.
315      */
createStreams()316     protected void createStreams() throws IOException {
317         input = transportSocket.getInputStream();
318         output = transportSocket.getOutputStream();
319     }
320 }
321