History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/jdi/SocketTransportService.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/jdi/SocketTransportService.java+536−0
@@ -0,0 +1,536 @@
1+/*
2+ * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package com.sun.tools.jdi;
27+
28+import com.sun.jdi.*;
29+import com.sun.jdi.connect.*;
30+import com.sun.jdi.connect.spi.*;
31+import java.net.*;
32+import java.io.*;
33+import java.util.Map;
34+import java.util.ResourceBundle;
35+
36+/*
37+ * A transport service based on a TCP connection between the
38+ * debugger and debugee.
39+ */
40+
41+public class SocketTransportService extends TransportService {
42+ private ResourceBundle messages = null;
43+
44+ /**
45+ * The listener returned by startListening encapsulates
46+ * the ServerSocket.
47+ */
48+ static class SocketListenKey extends ListenKey {
49+ ServerSocket ss;
50+
51+ SocketListenKey(ServerSocket ss) {
52+ this.ss = ss;
53+ }
54+
55+ ServerSocket socket() {
56+ return ss;
57+ }
58+
59+ /*
60+ * Returns the string representation of the address that this
61+ * listen key represents.
62+ */
63+ public String address() {
64+ InetAddress address = ss.getInetAddress();
65+
66+ /*
67+ * If bound to the wildcard address then use current local
68+ * hostname. In the event that we don't know our own hostname
69+ * then assume that host supports IPv4 and return something to
70+ * represent the loopback address.
71+ */
72+ if (address.isAnyLocalAddress()) {
73+ try {
74+ address = InetAddress.getLocalHost();
75+ } catch (UnknownHostException uhe) {
76+ byte[] loopback = {0x7f,0x00,0x00,0x01};
77+ try {
78+ address = InetAddress.getByAddress("127.0.0.1", loopback);
79+ } catch (UnknownHostException x) {
80+ throw new InternalError("unable to get local hostname");
81+ }
82+ }
83+ }
84+
85+ /*
86+ * Now decide if we return a hostname or IP address. Where possible
87+ * return a hostname but in the case that we are bound to an
88+ * address that isn't registered in the name service then we
89+ * return an address.
90+ */
91+ String result;
92+ String hostname = address.getHostName();
93+ String hostaddr = address.getHostAddress();
94+ if (hostname.equals(hostaddr)) {
95+ if (address instanceof Inet6Address) {
96+ result = "[" + hostaddr + "]";
97+ } else {
98+ result = hostaddr;
99+ }
100+ } else {
101+ result = hostname;
102+ }
103+
104+ /*
105+ * Finally return "hostname:port", "ipv4-address:port" or
106+ * "[ipv6-address]:port".
107+ */
108+ return result + ":" + ss.getLocalPort();
109+ }
110+
111+ public String toString() {
112+ return address();
113+ }
114+ }
115+
116+ /**
117+ * Handshake with the debuggee
118+ */
119+ void handshake(Socket s, long timeout) throws IOException {
120+ s.setSoTimeout((int)timeout);
121+
122+ byte[] hello = "JDWP-Handshake".getBytes("UTF-8");
123+ s.getOutputStream().write(hello);
124+
125+ byte[] b = new byte[hello.length];
126+ int received = 0;
127+ while (received < hello.length) {
128+ int n;
129+ try {
130+ n = s.getInputStream().read(b, received, hello.length-received);
131+ } catch (SocketTimeoutException x) {
132+ throw new IOException("handshake timeout");
133+ }
134+ if (n < 0) {
135+ s.close();
136+ throw new IOException("handshake failed - connection prematurally closed");
137+ }
138+ received += n;
139+ }
140+ for (int i=0; i<hello.length; i++) {
141+ if (b[i] != hello[i]) {
142+ throw new IOException("handshake failed - unrecognized message from target VM");
143+ }
144+ }
145+
146+ // disable read timeout
147+ s.setSoTimeout(0);
148+ }
149+
150+ /**
151+ * No-arg constructor
152+ */
153+ public SocketTransportService() {
154+ }
155+
156+ /**
157+ * The name of this transport service
158+ */
159+ public String name() {
160+ return "Socket";
161+ }
162+
163+ /**
164+ * Return localized description of this transport service
165+ */
166+ public String description() {
167+ synchronized (this) {
168+ if (messages == null) {
169+ messages = ResourceBundle.getBundle("com.sun.tools.jdi.resources.jdi");
170+ }
171+ }
172+ return messages.getString("socket_transportservice.description");
173+ }
174+
175+ /**
176+ * Return the capabilities of this transport service
177+ */
178+ public Capabilities capabilities() {
179+ return new SocketTransportServiceCapabilities();
180+ }
181+
182+
183+ /**
184+ * Attach to the specified address with optional attach and handshake
185+ * timeout.
186+ */
187+ public Connection attach(String address, long attachTimeout, long handshakeTimeout)
188+ throws IOException {
189+
190+ if (address == null) {
191+ throw new NullPointerException("address is null");
192+ }
193+ if (attachTimeout < 0 || handshakeTimeout < 0) {
194+ throw new IllegalArgumentException("timeout is negative");
195+ }
196+
197+ int splitIndex = address.indexOf(':');
198+ String host;
199+ String portStr;
200+ if (splitIndex < 0) {
201+ host = InetAddress.getLocalHost().getHostName();
202+ portStr = address;
203+ } else {
204+ host = address.substring(0, splitIndex);
205+ portStr = address.substring(splitIndex+1);
206+ }
207+
208+ int port;
209+ try {
210+ port = Integer.decode(portStr).intValue();
211+ } catch (NumberFormatException e) {
212+ throw new IllegalArgumentException(
213+ "unable to parse port number in address");
214+ }
215+
216+
217+ // open TCP connection to VM
218+
219+ InetSocketAddress sa = new InetSocketAddress(host, port);
220+ Socket s = new Socket();
221+ try {
222+ s.connect(sa, (int)attachTimeout);
223+ } catch (SocketTimeoutException exc) {
224+ try {
225+ s.close();
226+ } catch (IOException x) { }
227+ throw new TransportTimeoutException("timed out trying to establish connection");
228+ }
229+
230+ // handshake with the target VM
231+ try {
232+ handshake(s, handshakeTimeout);
233+ } catch (IOException exc) {
234+ try {
235+ s.close();
236+ } catch (IOException x) { }
237+ throw exc;
238+ }
239+
240+ return new SocketConnection(s);
241+ }
242+
243+ /*
244+ * Listen on the specified address and port. Return a listener
245+ * that encapsulates the ServerSocket.
246+ */
247+ ListenKey startListening(String localaddress, int port) throws IOException {
248+ InetSocketAddress sa;
249+ if (localaddress == null) {
250+ sa = new InetSocketAddress(port);
251+ } else {
252+ sa = new InetSocketAddress(localaddress, port);
253+ }
254+ ServerSocket ss = new ServerSocket();
255+ ss.bind(sa);
256+ return new SocketListenKey(ss);
257+ }
258+
259+ /**
260+ * Listen on the specified address
261+ */
262+ public ListenKey startListening(String address) throws IOException {
263+ // use ephemeral port if address isn't specified.
264+ if (address == null || address.length() == 0) {
265+ address = "0";
266+ }
267+
268+ int splitIndex = address.indexOf(':');
269+ String localaddr = null;
270+ if (splitIndex >= 0) {
271+ localaddr = address.substring(0, splitIndex);
272+ address = address.substring(splitIndex+1);
273+ }
274+
275+ int port;
276+ try {
277+ port = Integer.decode(address).intValue();
278+ } catch (NumberFormatException e) {
279+ throw new IllegalArgumentException(
280+ "unable to parse port number in address");
281+ }
282+
283+ return startListening(localaddr, port);
284+ }
285+
286+ /**
287+ * Listen on the default address
288+ */
289+ public ListenKey startListening() throws IOException {
290+ return startListening(null, 0);
291+ }
292+
293+ /**
294+ * Stop the listener
295+ */
296+ public void stopListening(ListenKey listener) throws IOException {
297+ if (!(listener instanceof SocketListenKey)) {
298+ throw new IllegalArgumentException("Invalid listener");
299+ }
300+
301+ synchronized (listener) {
302+ ServerSocket ss = ((SocketListenKey)listener).socket();
303+
304+ // if the ServerSocket has been closed it means
305+ // the listener is invalid
306+ if (ss.isClosed()) {
307+ throw new IllegalArgumentException("Invalid listener");
308+ }
309+ ss.close();
310+ }
311+ }
312+
313+ /**
314+ * Accept a connection from a debuggee and handshake with it.
315+ */
316+ public Connection accept(ListenKey listener, long acceptTimeout, long handshakeTimeout) throws IOException {
317+ if (acceptTimeout < 0 || handshakeTimeout < 0) {
318+ throw new IllegalArgumentException("timeout is negative");
319+ }
320+ if (!(listener instanceof SocketListenKey)) {
321+ throw new IllegalArgumentException("Invalid listener");
322+ }
323+ ServerSocket ss;
324+
325+ // obtain the ServerSocket from the listener - if the
326+ // socket is closed it means the listener is invalid
327+ synchronized (listener) {
328+ ss = ((SocketListenKey)listener).socket();
329+ if (ss.isClosed()) {
330+ throw new IllegalArgumentException("Invalid listener");
331+ }
332+ }
333+
334+ // from here onwards it's possible that the ServerSocket
335+ // may be closed by a call to stopListening - that's okay
336+ // because the ServerSocket methods will throw an
337+ // IOException indicating the socket is closed.
338+ //
339+ // Additionally, it's possible that another thread calls accept
340+ // with a different accept timeout - that creates a same race
341+ // condition between setting the timeout and calling accept.
342+ // As it is such an unlikely scenario (requires both threads
343+ // to be using the same listener we've chosen to ignore the issue).
344+
345+ ss.setSoTimeout((int)acceptTimeout);
346+ Socket s;
347+ try {
348+ s = ss.accept();
349+ } catch (SocketTimeoutException x) {
350+ throw new TransportTimeoutException("timeout waiting for connection");
351+ }
352+
353+ // handshake here
354+ handshake(s, handshakeTimeout);
355+
356+ return new SocketConnection(s);
357+ }
358+
359+ public String toString() {
360+ return name();
361+ }
362+}
363+
364+
365+/*
366+ * The Connection returned by attach and accept is one of these
367+ */
368+class SocketConnection extends Connection {
369+ private Socket socket;
370+ private boolean closed = false;
371+ private OutputStream socketOutput;
372+ private InputStream socketInput;
373+ private Object receiveLock = new Object();
374+ private Object sendLock = new Object();
375+ private Object closeLock = new Object();
376+
377+ SocketConnection(Socket socket) throws IOException {
378+ this.socket = socket;
379+ socket.setTcpNoDelay(true);
380+ socketInput = socket.getInputStream();
381+ socketOutput = socket.getOutputStream();
382+ }
383+
384+ public void close() throws IOException {
385+ synchronized (closeLock) {
386+ if (closed) {
387+ return;
388+ }
389+ socketOutput.close();
390+ socketInput.close();
391+ socket.close();
392+ closed = true;
393+ }
394+ }
395+
396+ public boolean isOpen() {
397+ synchronized (closeLock) {
398+ return !closed;
399+ }
400+ }
401+
402+ public byte[] readPacket() throws IOException {
403+ if (!isOpen()) {
404+ throw new ClosedConnectionException("connection is closed");
405+ }
406+ synchronized (receiveLock) {
407+ int b1,b2,b3,b4;
408+
409+ // length
410+ try {
411+ b1 = socketInput.read();
412+ b2 = socketInput.read();
413+ b3 = socketInput.read();
414+ b4 = socketInput.read();
415+ } catch (IOException ioe) {
416+ if (!isOpen()) {
417+ throw new ClosedConnectionException("connection is closed");
418+ } else {
419+ throw ioe;
420+ }
421+ }
422+
423+ // EOF
424+ if (b1<0) {
425+ return new byte[0];
426+ }
427+
428+ if (b2<0 || b3<0 || b4<0) {
429+ throw new IOException("protocol error - premature EOF");
430+ }
431+
432+ int len = ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4 << 0));
433+
434+ if (len < 0) {
435+ throw new IOException("protocol error - invalid length");
436+ }
437+
438+ byte b[] = new byte[len];
439+ b[0] = (byte)b1;
440+ b[1] = (byte)b2;
441+ b[2] = (byte)b3;
442+ b[3] = (byte)b4;
443+
444+ int off = 4;
445+ len -= off;
446+
447+ while (len > 0) {
448+ int count;
449+ try {
450+ count = socketInput.read(b, off, len);
451+ } catch (IOException ioe) {
452+ if (!isOpen()) {
453+ throw new ClosedConnectionException("connection is closed");
454+ } else {
455+ throw ioe;
456+ }
457+ }
458+ if (count < 0) {
459+ throw new IOException("protocol error - premature EOF");
460+ }
461+ len -= count;
462+ off += count;
463+ }
464+
465+ return b;
466+ }
467+ }
468+
469+ public void writePacket(byte b[]) throws IOException {
470+ if (!isOpen()) {
471+ throw new ClosedConnectionException("connection is closed");
472+ }
473+
474+ /*
475+ * Check the packet size
476+ */
477+ if (b.length < 11) {
478+ throw new IllegalArgumentException("packet is insufficient size");
479+ }
480+ int b0 = b[0] & 0xff;
481+ int b1 = b[1] & 0xff;
482+ int b2 = b[2] & 0xff;
483+ int b3 = b[3] & 0xff;
484+ int len = ((b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << 0));
485+ if (len < 11) {
486+ throw new IllegalArgumentException("packet is insufficient size");
487+ }
488+
489+ /*
490+ * Check that the byte array contains the complete packet
491+ */
492+ if (len > b.length) {
493+ throw new IllegalArgumentException("length mis-match");
494+ }
495+
496+ synchronized (sendLock) {
497+ try {
498+ /*
499+ * Send the packet (ignoring any bytes that follow
500+ * the packet in the byte array).
501+ */
502+ socketOutput.write(b, 0, len);
503+ } catch (IOException ioe) {
504+ if (!isOpen()) {
505+ throw new ClosedConnectionException("connection is closed");
506+ } else {
507+ throw ioe;
508+ }
509+ }
510+ }
511+ }
512+}
513+
514+
515+/*
516+ * The capabilities of the socket transport service
517+ */
518+class SocketTransportServiceCapabilities extends TransportService.Capabilities {
519+
520+ public boolean supportsMultipleConnections() {
521+ return true;
522+ }
523+
524+ public boolean supportsAttachTimeout() {
525+ return true;
526+ }
527+
528+ public boolean supportsAcceptTimeout() {
529+ return true;
530+ }
531+
532+ public boolean supportsHandshakeTimeout() {
533+ return true;
534+ }
535+
536+}