Skip to content

Commit 5ed00d4

Browse files
lhchavezZabot
authored andcommitted
Always bind to localhost for connectors
This change makes it such that we always bind on a localhost interface to avoid repls being marked as being servers when they just want to debug. This is a tiny bit of a hack, but this was needed to avoid relying on a modified Eclipse JDT.
1 parent 336d090 commit 5ed00d4

File tree

7 files changed

+767
-2
lines changed

7 files changed

+767
-2
lines changed

com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedLaunchingConnector.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import org.eclipse.jdi.internal.VirtualMachineImpl;
2121
import org.eclipse.jdi.internal.VirtualMachineManagerImpl;
2222
import org.eclipse.jdi.internal.connect.SocketLaunchingConnectorImpl;
23-
import org.eclipse.jdi.internal.connect.SocketListeningConnectorImpl;
2423

2524
import com.microsoft.java.debug.core.DebugUtility;
2625
import com.sun.jdi.VirtualMachine;
@@ -76,7 +75,7 @@ public VirtualMachine launch(Map<String, ? extends Argument> connectionArgs)
7675
// do nothing.
7776
}
7877

79-
SocketListeningConnectorImpl listenConnector = new SocketListeningConnectorImpl(
78+
LocalhostSocketListeningConnector listenConnector = new LocalhostSocketListeningConnector(
8079
virtualMachineManager());
8180
Map<String, Connector.Argument> args = listenConnector.defaultArguments();
8281
((Connector.IntegerArgument) args.get("timeout")).setValue(ACCEPT_TIMEOUT); //$NON-NLS-1$
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2017-2021 Microsoft Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Microsoft Corporation - initial API and implementation
10+
*******************************************************************************/
11+
12+
package com.microsoft.java.debug.plugin.internal;
13+
14+
import java.io.File;
15+
import java.io.IOException;
16+
import java.nio.file.Files;
17+
import java.nio.file.Paths;
18+
import java.util.Map;
19+
20+
import org.eclipse.jdi.internal.VirtualMachineManagerImpl;
21+
import org.eclipse.jdi.internal.connect.ConnectMessages;
22+
import org.eclipse.jdi.internal.connect.SocketListeningConnectorImpl;
23+
import org.eclipse.jdi.internal.connect.SocketTransportImpl;
24+
25+
import com.sun.jdi.VirtualMachine;
26+
import com.sun.jdi.connect.Connector;
27+
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
28+
import com.sun.jdi.connect.ListeningConnector;
29+
30+
/**
31+
* An advanced launching connector that supports cwd and enviroment variables.
32+
*
33+
*/
34+
public class AdvancedListeningConnector extends SocketListeningConnectorImpl implements ListeningConnector {
35+
private static final int ACCEPT_TIMEOUT = 10 * 1000;
36+
37+
public AdvancedListeningConnector(VirtualMachineManagerImpl virtualMachineManager) {
38+
super(virtualMachineManager);
39+
40+
// Create communication protocol specific transport.
41+
this.fTransport = new LocalhostSocketTransport();
42+
}
43+
44+
@Override
45+
public String name() {
46+
return "com.microsoft.java.debug.AdvancedListeningConnector";
47+
}
48+
49+
/**
50+
* Retrieves connection port.
51+
*/
52+
private int getConnectionPort(Map<String, ? extends Connector.Argument> connectionArgs) throws IllegalConnectorArgumentsException {
53+
String attribute = "port"; //$NON-NLS-1$
54+
try {
55+
// If listening port is not specified, use port 0
56+
IntegerArgument argument = (IntegerArgument) connectionArgs
57+
.get(attribute);
58+
if (argument != null && argument.value() != null) {
59+
return argument.intValue();
60+
} else {
61+
return 0;
62+
}
63+
} catch (ClassCastException e) {
64+
throw new IllegalConnectorArgumentsException(
65+
ConnectMessages.SocketListeningConnectorImpl_Connection_argument_is_not_of_the_right_type_6,
66+
attribute);
67+
} catch (NullPointerException e) {
68+
throw new IllegalConnectorArgumentsException(
69+
ConnectMessages.SocketListeningConnectorImpl_Necessary_connection_argument_is_null_7,
70+
attribute);
71+
} catch (NumberFormatException e) {
72+
throw new IllegalConnectorArgumentsException(
73+
ConnectMessages.SocketListeningConnectorImpl_Connection_argument_is_not_a_number_8,
74+
attribute);
75+
}
76+
}
77+
78+
/**
79+
* Listens for one or more connections initiated by target VMs.
80+
*
81+
* @return Returns the address at which the connector is listening for a
82+
* connection.
83+
*/
84+
@Override
85+
public String startListening(Map<String, ? extends Connector.Argument> connectionArgs) throws IOException, IllegalConnectorArgumentsException {
86+
int port = getConnectionPort(connectionArgs);
87+
String result = null;
88+
try {
89+
result = ((LocalhostSocketTransport) fTransport).startListening(port);
90+
} catch (IllegalArgumentException e) {
91+
throw new IllegalConnectorArgumentsException(
92+
ConnectMessages.SocketListeningConnectorImpl_ListeningConnector_Socket_Port,
93+
"port"); //$NON-NLS-1$
94+
}
95+
return result;
96+
}
97+
98+
/* (non-Javadoc)
99+
* @see com.sun.jdi.connect.ListeningConnector#stopListening(java.util.Map)
100+
*/
101+
@Override
102+
public void stopListening(Map<String, ? extends Connector.Argument> connectionArgs) throws IOException {
103+
((LocalhostSocketTransport) fTransport).stopListening();
104+
}
105+
106+
/**
107+
* Waits for a target VM to attach to this connector.
108+
*
109+
* @return Returns a connected Virtual Machine.
110+
*/
111+
@Override
112+
public VirtualMachine accept(Map<String, ? extends Connector.Argument> connectionArgs) throws IOException, IllegalConnectorArgumentsException {
113+
LocalhostSocketConnection connection = (LocalhostSocketConnection) ((LocalhostSocketTransport) fTransport)
114+
.accept(ACCEPT_TIMEOUT, 0);
115+
return establishedConnection(connection);
116+
}
117+
}

com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedVirtualMachineManager.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.sun.jdi.VirtualMachine;
2222
import com.sun.jdi.VirtualMachineManager;
2323
import com.sun.jdi.connect.LaunchingConnector;
24+
import com.sun.jdi.connect.ListeningConnector;
2425

2526
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
2627
import org.eclipse.core.runtime.preferences.InstanceScope;
@@ -46,6 +47,14 @@ public List<LaunchingConnector> launchingConnectors() {
4647
return connectors;
4748
}
4849

50+
@Override
51+
public List<ListeningConnector> listeningConnectors() {
52+
List<ListeningConnector> connectors = new ArrayList<>();
53+
connectors.add(new AdvancedListeningConnector(this));
54+
connectors.addAll(super.listeningConnectors());
55+
return connectors;
56+
}
57+
4958
@Override
5059
public void update(DebugSettings oldSettings, DebugSettings newSettings) {
5160
int currentTimeout = getGlobalRequestTimeout();
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/**
2+
* Copyright (c) 2000, 2016 IBM Corporation and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation - initial API and implementation
13+
* Google Inc - add support for accepting multiple connections
14+
*******************************************************************************/
15+
package com.microsoft.java.debug.plugin.internal;
16+
17+
import java.io.DataInputStream;
18+
import java.io.IOException;
19+
import java.io.InputStream;
20+
import java.io.OutputStream;
21+
import java.net.Socket;
22+
23+
import org.eclipse.jdi.internal.connect.SocketConnection;
24+
25+
import com.sun.jdi.connect.spi.ClosedConnectionException;
26+
import com.sun.jdi.connect.spi.Connection;
27+
28+
public class LocalhostSocketConnection extends Connection {
29+
// for attaching connector
30+
private Socket fSocket;
31+
32+
private InputStream fInput;
33+
34+
private OutputStream fOutput;
35+
36+
LocalhostSocketConnection(Socket socket, InputStream in, OutputStream out) {
37+
fSocket = socket;
38+
fInput = in;
39+
fOutput = out;
40+
}
41+
42+
/*
43+
* (non-Javadoc)
44+
*
45+
* @see com.sun.jdi.connect.spi.Connection#close()
46+
*/
47+
@Override
48+
public synchronized void close() throws IOException {
49+
if (fSocket == null)
50+
return;
51+
52+
fSocket.close();
53+
fSocket = null;
54+
}
55+
56+
/*
57+
* (non-Javadoc)
58+
*
59+
* @see com.sun.jdi.connect.spi.Connection#isOpen()
60+
*/
61+
@Override
62+
public synchronized boolean isOpen() {
63+
return fSocket != null;
64+
}
65+
66+
/*
67+
* (non-Javadoc)
68+
*
69+
* @see com.sun.jdi.connect.spi.Connection#readPacket()
70+
*/
71+
@Override
72+
public byte[] readPacket() throws IOException {
73+
DataInputStream stream;
74+
synchronized (this) {
75+
if (!isOpen()) {
76+
throw new ClosedConnectionException();
77+
}
78+
stream = new DataInputStream(fInput);
79+
}
80+
synchronized (stream) {
81+
int packetLength = 0;
82+
try {
83+
packetLength = stream.readInt();
84+
} catch (IOException e) {
85+
throw new ClosedConnectionException();
86+
}
87+
88+
if (packetLength < 11) {
89+
throw new IOException("JDWP Packet under 11 bytes"); //$NON-NLS-1$
90+
}
91+
92+
byte[] packet = new byte[packetLength];
93+
packet[0] = (byte) ((packetLength >>> 24) & 0xFF);
94+
packet[1] = (byte) ((packetLength >>> 16) & 0xFF);
95+
packet[2] = (byte) ((packetLength >>> 8) & 0xFF);
96+
packet[3] = (byte) ((packetLength >>> 0) & 0xFF);
97+
98+
stream.readFully(packet, 4, packetLength - 4);
99+
return packet;
100+
}
101+
}
102+
103+
/*
104+
* (non-Javadoc)
105+
*
106+
* @see com.sun.jdi.connect.spi.Connection#writePacket(byte[])
107+
*/
108+
@Override
109+
public void writePacket(byte[] packet) throws IOException {
110+
if (!isOpen()) {
111+
throw new ClosedConnectionException();
112+
}
113+
if (packet == null) {
114+
throw new IllegalArgumentException(
115+
"Invalid JDWP Packet, packet cannot be null"); //$NON-NLS-1$
116+
}
117+
if (packet.length < 11) {
118+
throw new IllegalArgumentException(
119+
"Invalid JDWP Packet, must be at least 11 bytes. PacketSize:" + packet.length); //$NON-NLS-1$
120+
}
121+
122+
int packetSize = getPacketLength(packet);
123+
if (packetSize < 11) {
124+
throw new IllegalArgumentException(
125+
"Invalid JDWP Packet, must be at least 11 bytes. PacketSize:" + packetSize); //$NON-NLS-1$
126+
}
127+
128+
if (packetSize > packet.length) {
129+
throw new IllegalArgumentException(
130+
"Invalid JDWP packet: Specified length is greater than actual length"); //$NON-NLS-1$
131+
}
132+
133+
OutputStream stream = null;
134+
synchronized (this) {
135+
if (!isOpen()) {
136+
throw new ClosedConnectionException();
137+
}
138+
stream = fOutput;
139+
}
140+
141+
synchronized (stream) {
142+
// packet.length can be > packetSize. Sending too much will cause
143+
// errors on the other side
144+
stream.write(packet, 0, packetSize);
145+
}
146+
}
147+
148+
private int getPacketLength(byte[] packet) {
149+
int len = 0;
150+
if (packet.length >= 4) {
151+
len = (((packet[0] & 0xFF) << 24) + ((packet[1] & 0xFF) << 16)
152+
+ ((packet[2] & 0xFF) << 8) + ((packet[3] & 0xFF) << 0));
153+
}
154+
return len;
155+
}
156+
}

0 commit comments

Comments
 (0)