22 * or visit www.oracle.com if you need additional information or have any |
22 * or visit www.oracle.com if you need additional information or have any |
23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 package jdk.jshell.execution; |
25 package jdk.jshell.execution; |
26 |
26 |
27 import java.io.ByteArrayOutputStream; |
|
28 import java.io.IOException; |
27 import java.io.IOException; |
29 import java.io.InputStream; |
28 import java.io.InputStream; |
30 import java.io.ObjectInput; |
29 import java.io.ObjectInput; |
31 import java.io.ObjectOutput; |
30 import java.io.ObjectOutput; |
32 import java.io.OutputStream; |
31 import java.io.OutputStream; |
33 import java.net.InetAddress; |
32 import java.net.InetAddress; |
34 import java.net.ServerSocket; |
33 import java.net.ServerSocket; |
35 import java.net.Socket; |
34 import java.net.Socket; |
36 import java.security.SecureRandom; |
|
37 import java.util.ArrayList; |
35 import java.util.ArrayList; |
38 import java.util.Arrays; |
|
39 import java.util.HashMap; |
36 import java.util.HashMap; |
40 import java.util.List; |
37 import java.util.List; |
41 import java.util.Map; |
38 import java.util.Map; |
42 import java.util.function.Consumer; |
39 import java.util.function.Consumer; |
43 |
|
44 import com.sun.jdi.BooleanValue; |
40 import com.sun.jdi.BooleanValue; |
45 import com.sun.jdi.ClassNotLoadedException; |
41 import com.sun.jdi.ClassNotLoadedException; |
46 import com.sun.jdi.Field; |
42 import com.sun.jdi.Field; |
47 import com.sun.jdi.IncompatibleThreadStateException; |
43 import com.sun.jdi.IncompatibleThreadStateException; |
48 import com.sun.jdi.InvalidTypeException; |
44 import com.sun.jdi.InvalidTypeException; |
125 JdiInitiator jdii = new JdiInitiator(port, |
121 JdiInitiator jdii = new JdiInitiator(port, |
126 env.extraRemoteVMOptions(), REMOTE_AGENT, isLaunch, host); |
122 env.extraRemoteVMOptions(), REMOTE_AGENT, isLaunch, host); |
127 VirtualMachine vm = jdii.vm(); |
123 VirtualMachine vm = jdii.vm(); |
128 Process process = jdii.process(); |
124 Process process = jdii.process(); |
129 |
125 |
130 OutputStream processOut = process.getOutputStream(); |
|
131 SecureRandom rng = new SecureRandom(); |
|
132 byte[] randomBytes = new byte[VERIFY_HASH_LEN]; |
|
133 |
|
134 rng.nextBytes(randomBytes); |
|
135 processOut.write(randomBytes); |
|
136 processOut.flush(); |
|
137 |
|
138 List<Consumer<String>> deathListeners = new ArrayList<>(); |
126 List<Consumer<String>> deathListeners = new ArrayList<>(); |
139 deathListeners.add(s -> env.closeDown()); |
127 deathListeners.add(s -> env.closeDown()); |
140 Util.detectJdiExitEvent(vm, s -> { |
128 Util.detectJdiExitEvent(vm, s -> { |
141 for (Consumer<String> h : deathListeners) { |
129 for (Consumer<String> h : deathListeners) { |
142 h.accept(s); |
130 h.accept(s); |
143 } |
131 } |
144 }); |
132 }); |
145 |
|
146 ByteArrayOutputStream receivedRandomBytes = new ByteArrayOutputStream(); |
|
147 |
133 |
148 // Set-up the commands/reslts on the socket. Piggy-back snippet |
134 // Set-up the commands/reslts on the socket. Piggy-back snippet |
149 // output. |
135 // output. |
150 Socket socket = listener.accept(); |
136 Socket socket = listener.accept(); |
151 // out before in -- match remote creation so we don't hang |
137 // out before in -- match remote creation so we don't hang |
152 OutputStream out = socket.getOutputStream(); |
138 OutputStream out = socket.getOutputStream(); |
153 Map<String, OutputStream> outputs = new HashMap<>(); |
139 Map<String, OutputStream> outputs = new HashMap<>(); |
154 outputs.put("out", env.userOut()); |
140 outputs.put("out", env.userOut()); |
155 outputs.put("err", env.userErr()); |
141 outputs.put("err", env.userErr()); |
156 outputs.put("echo", new OutputStream() { |
|
157 @Override public void write(int b) throws IOException { |
|
158 synchronized (receivedRandomBytes) { |
|
159 receivedRandomBytes.write(b); |
|
160 receivedRandomBytes.notify(); |
|
161 } |
|
162 } |
|
163 }); |
|
164 Map<String, InputStream> input = new HashMap<>(); |
142 Map<String, InputStream> input = new HashMap<>(); |
165 input.put("in", env.userIn()); |
143 input.put("in", env.userIn()); |
166 return remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> { |
144 return remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> new JdiDefaultExecutionControl(objOut, objIn, vm, process, deathListeners)); |
167 synchronized (receivedRandomBytes) { |
145 } |
168 while (receivedRandomBytes.size() < randomBytes.length) { |
146 } |
169 try { |
|
170 receivedRandomBytes.wait(); |
|
171 } catch (InterruptedException ex) { |
|
172 //ignore |
|
173 } |
|
174 } |
|
175 if (!Arrays.equals(receivedRandomBytes.toByteArray(), randomBytes)) { |
|
176 throw new IllegalStateException("Invalid connection!"); |
|
177 } |
|
178 } |
|
179 return new JdiDefaultExecutionControl(objOut, objIn, vm, process, deathListeners); |
|
180 }); |
|
181 } |
|
182 } |
|
183 //where: |
|
184 private static final int VERIFY_HASH_LEN = 20; |
|
185 |
147 |
186 /** |
148 /** |
187 * Create an instance. |
149 * Create an instance. |
188 * |
150 * |
189 * @param cmdout the output for commands |
151 * @param cmdout the output for commands |