1 /*
2  * Copyright (c) 2003, 2018, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package nsk.jdi.VirtualMachineManager.createVirtualMachine;
25 
26 import com.sun.jdi.*;
27 import com.sun.jdi.connect.*;
28 import com.sun.jdi.connect.spi.*;
29 import java.net.*;
30 import java.io.*;
31 import java.util.*;
32 
33 /*
34  * A transport service implementation based on a TCP connection used by
35  * nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM002 test.
36  * It is borrowed from the com.sun.tools.jdi.SocketTransportService
37  */
38 
39 public class CreateVM002_TranspServ extends TransportService {
40 
41     /**
42      * The listener returned by startListening encapsulates
43      * the ServerSocket.
44      */
45     static class SocketListenKey extends ListenKey {
46         ServerSocket ss;
47 
SocketListenKey(ServerSocket ss)48         SocketListenKey(ServerSocket ss) {
49             this.ss = ss;
50         }
51 
socket()52         ServerSocket socket() {
53             return ss;
54         }
55 
address()56         public String address() {
57             InetAddress localaddr = ss.getInetAddress();
58             int port = ss.getLocalPort();
59             if (localaddr.isAnyLocalAddress()) {
60                 return "" + port;
61             } else {
62                 return localaddr + ":" + port;
63             }
64         }
65 
toString()66         public String toString() {
67             return address();
68         }
69     }
70 
71     /**
72      * Handshake with the debuggee
73      */
handshake(Socket s, long timeout)74     void handshake(Socket s, long timeout) throws IOException {
75         s.setSoTimeout((int)timeout);
76 
77         byte[] hello = "JDWP-Handshake".getBytes("UTF-8");
78         s.getOutputStream().write(hello);
79 
80         byte[] b = new byte[hello.length];
81         int received = 0;
82         while (received < hello.length) {
83             int n;
84             try {
85                 n = s.getInputStream().read(b, received, hello.length-received);
86             } catch (SocketTimeoutException x) {
87                 throw new IOException("##> CreateVM002_TranspServ: Handshake timeout");
88             }
89             if (n < 0) {
90                 s.close();
91                 throw new IOException
92                     ("##> CreateVM002_TranspServ: Handshake FAILED - connection prematurally closed!");
93             }
94             received += n;
95         }
96         for (int i=0; i<hello.length; i++) {
97             if (b[i] != hello[i]) {
98                 throw new IOException
99                     ("##> CreateVM002_TranspServ: Handshake FAILED - unrecognized message from target VM");
100             }
101         }
102 
103         // disable read timeout
104         s.setSoTimeout(0);
105     }
106 
107     /**
108      * No-arg constructor
109      */
CreateVM002_TranspServ()110     public CreateVM002_TranspServ() {
111     }
112 
113     /**
114      * The name of this transport service
115      */
name()116     public String name() {
117         return "CreateVM002_TranspServ";
118     }
119 
120     /**
121      * The description of this transport service
122      */
description()123     public String description() {
124         return "SocketTransportService for nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM002 test.";
125     }
126 
127     /**
128      * Return the capabilities of this transport service
129      */
capabilities()130     public Capabilities capabilities() {
131         return new CreateVM002_TranspServCapabilities();
132     }
133 
134 
135     /**
136      * Attach to the specified address with optional attach and handshake
137      * timeout.
138      */
attach(String address, long attachTimeout, long handshakeTimeout)139     public Connection attach(String address, long attachTimeout, long handshakeTimeout)
140         throws IOException {
141 
142         if (address == null) {
143             throw new NullPointerException("##> CreateVM002_TranspServ: attach() - address is null");
144         }
145         if (attachTimeout < 0 || handshakeTimeout < 0) {
146             throw new IllegalArgumentException("##> CreateVM002_TranspServ: attach() - timeout is negative");
147         }
148 
149         int splitIndex = address.indexOf(':');
150         String host;
151         String portStr;
152         if (splitIndex < 0) {
153             host = InetAddress.getLocalHost().getHostName();
154             portStr = address;
155         } else {
156             host = address.substring(0, splitIndex);
157             portStr = address.substring(splitIndex+1);
158         }
159 
160         int port;
161         try {
162             port = Integer.decode(portStr).intValue();
163         } catch (NumberFormatException e) {
164             throw new IllegalArgumentException(
165                 "##> CreateVM002_TranspServ: attach() - unable to parse port number in address");
166         }
167 
168 
169         // open TCP connection to VM
170 
171         InetSocketAddress sa = new InetSocketAddress(host, port);
172         Socket s = new Socket();
173         try {
174             s.connect(sa, (int)attachTimeout);
175         } catch (SocketTimeoutException exc) {
176             try {
177                 s.close();
178             } catch (IOException x) { }
179             throw new TransportTimeoutException
180                 ("##> CreateVM002_TranspServ: attach() - timed out trying to establish connection");
181         }
182 
183         // handshake with the target VM
184         try {
185             handshake(s, handshakeTimeout);
186         } catch (IOException exc) {
187             try {
188                 s.close();
189             } catch (IOException x) { }
190             throw exc;
191         }
192 
193         return new CreateVM002_Connection(s);
194     }
195 
196     /*
197      * Listen on the specified address and port. Return a listener
198      * that encapsulates the ServerSocket.
199      */
startListening(String localaddress, int port)200     ListenKey startListening(String localaddress, int port) throws IOException {
201         InetSocketAddress sa;
202         if (localaddress == null) {
203             sa = new InetSocketAddress(port);
204         } else {
205             sa = new InetSocketAddress(localaddress, port);
206         }
207         ServerSocket ss = new ServerSocket();
208         // if port is 0 do not set the SO_REUSEADDR flag
209         if (port == 0) {
210             ss.setReuseAddress(false);
211         }
212         ss.bind(sa);
213         return new SocketListenKey(ss);
214     }
215 
216     /**
217      * Listen on the specified address
218      */
startListening(String address)219     public ListenKey startListening(String address) throws IOException {
220         // use ephemeral port if address isn't specified.
221         if (address == null || address.length() == 0) {
222             address = "0";
223         }
224 
225         int splitIndex = address.indexOf(':');
226         String localaddr = null;
227         if (splitIndex >= 0) {
228             localaddr = address.substring(0, splitIndex);
229             address = address.substring(splitIndex+1);
230         }
231 
232         int port;
233         try {
234             port = Integer.decode(address).intValue();
235         } catch (NumberFormatException e) {
236             throw new IllegalArgumentException(
237                     "##> CreateVM002_TranspServ: startListening() - unable to parse port number in address");
238         }
239 
240         return startListening(localaddr, port);
241     }
242 
243     /**
244      * Listen on the default address
245      */
startListening()246     public ListenKey startListening() throws IOException {
247         return startListening(null, 0);
248     }
249 
250     /**
251      * Stop the listener
252      */
stopListening(ListenKey listener)253     public void stopListening(ListenKey listener) throws IOException {
254         if (!(listener instanceof SocketListenKey)) {
255             throw new IllegalArgumentException
256                 ("##> CreateVM002_TranspServ: stopListening() - Invalid listener");
257         }
258 
259         synchronized (listener) {
260             ServerSocket ss = ((SocketListenKey)listener).socket();
261 
262             // if the ServerSocket has been closed it means
263             // the listener is invalid
264             if (ss.isClosed()) {
265                 throw new IllegalArgumentException
266                     ("##> CreateVM002_TranspServ: stopListening() - Invalid listener");
267             }
268             ss.close();
269         }
270     }
271 
272     /**
273      * Accept a connection from a debuggee and handshake with it.
274      */
accept(ListenKey listener, long acceptTimeout, long handshakeTimeout)275     public Connection accept(ListenKey listener, long acceptTimeout, long handshakeTimeout) throws IOException {
276         if (acceptTimeout < 0 || handshakeTimeout < 0) {
277             throw new IllegalArgumentException
278                 ("##> CreateVM002_TranspServ: accept() - timeout is negative");
279         }
280         if (!(listener instanceof SocketListenKey)) {
281             throw new IllegalArgumentException
282                 ("##> CreateVM002_TranspServ: accept() - Invalid listener");
283         }
284         ServerSocket ss;
285 
286         // obtain the ServerSocket from the listener - if the
287         // socket is closed it means the listener is invalid
288         synchronized (listener) {
289             ss = ((SocketListenKey)listener).socket();
290             if (ss.isClosed()) {
291                throw new IllegalArgumentException
292                    ("##> CreateVM002_TranspServ: accept() - Invalid listener");
293             }
294         }
295 
296         ss.setSoTimeout((int)acceptTimeout);
297         Socket s;
298         try {
299             s = ss.accept();
300         } catch (SocketTimeoutException x) {
301             throw new TransportTimeoutException
302                 ("##> CreateVM002_TranspServ: accept() - timeout waiting for connection");
303         }
304 
305         // handshake here
306         handshake(s, handshakeTimeout);
307 
308         return new CreateVM002_Connection(s);
309     }
310 
toString()311     public String toString() {
312        return name();
313     }
314 } // end of CreateVM002_TranspServ class
315 
316 class CreateVM002_Connection extends Connection {
317     private Socket socket;
318     private boolean closed = false;
319     private OutputStream socketOutput;
320     private InputStream socketInput;
321     private Object receiveLock = new Object();
322     private Object sendLock = new Object();
323     private Object closeLock = new Object();
324     private boolean toPrintPacket = false;
325     private int readPacketRequestNumber = 0;
326     private int writePacketRequestNumber = 0;
327     public boolean wasIOException = false;
328 
CreateVM002_Connection(Socket socket)329     CreateVM002_Connection(Socket socket) throws IOException {
330         this.socket = socket;
331         socket.setTcpNoDelay(true);
332         socketInput = socket.getInputStream();
333         socketOutput = socket.getOutputStream();
334     }
335 
close()336     public void close() throws IOException {
337         synchronized (closeLock) {
338            if (closed) {
339                 return;
340            }
341            socketOutput.close();
342            socketInput.close();
343            socket.close();
344            closed = true;
345         }
346     }
347 
isOpen()348     public boolean isOpen() {
349         synchronized (closeLock) {
350             return !closed;
351         }
352     }
353 
readPacket()354     public byte[] readPacket() throws IOException {
355         if (!isOpen()) {
356             throw new ClosedConnectionException
357                 ("##> CreateVM002_Connection: readPacket() - connection is closed: N1");
358         }
359         synchronized (receiveLock) {
360             int b1,b2,b3,b4;
361 
362             // length
363             try {
364                 b1 = socketInput.read();
365                 b2 = socketInput.read();
366                 b3 = socketInput.read();
367                 b4 = socketInput.read();
368             } catch (IOException ioe) {
369                 if (!isOpen()) {
370                     throw new ClosedConnectionException
371                         ("##> CreateVM002_Connection: readPacket() - connection is closed: N2");
372                 } else {
373                     throw ioe;
374                 }
375             }
376 
377             if (b1<0 || b2<0 || b3<0 || b4<0)
378                 throw new EOFException();
379 
380             int len = ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4 << 0));
381 
382             if (len < 0) {
383                 throw new IOException
384                     ("##> CreateVM002_Connection: readPacket() - protocol error: invalid Packet's length");
385             }
386 
387             byte b[] = new byte[len];
388             b[0] = (byte)b1;
389             b[1] = (byte)b2;
390             b[2] = (byte)b3;
391             b[3] = (byte)b4;
392 
393             int off = 4;
394             len -= off;
395 
396             while (len > 0) {
397                 int count;
398                 try {
399                     count = socketInput.read(b, off, len);
400                 } catch (IOException ioe) {
401                     if (!isOpen()) {
402                         throw new ClosedConnectionException
403                             ("##> CreateVM002_Connection: readPacket() - connection is closed: N3");
404                     } else {
405                         throw ioe;
406                     }
407                 }
408                 if (count < 0) {
409                     throw new EOFException
410                         ("##> CreateVM002_Connection: readPacket() - read() method returns negative value");
411                 }
412                 len -= count;
413                 off += count;
414             }
415 
416             readPacketRequestNumber++;
417             if ( readPacketRequestNumber == -1 ) {
418                 throw new IOException
419                     ("Dummy IOException in CreateVM002_Connection.readPacket(); readPacketRequestNumber = "
420                     + readPacketRequestNumber);
421             }
422             printPacket("readPacket:", b);
423             return b;
424         }
425     }
426 
writePacket(byte b[])427     public void writePacket(byte b[]) throws IOException {
428         writePacketRequestNumber++;
429         if ( writePacketRequestNumber == 2 ) {
430             wasIOException = true;
431             throw new IOException
432                 ("Dummy IOException in CreateVM002_Connection.writePacket(); writePacketRequestNumber = "
433                 + writePacketRequestNumber);
434         }
435         if (!isOpen()) {
436             throw new ClosedConnectionException
437                 ("##> CreateVM002_Connection: writePacket() - connection is closed: N1");
438         }
439 
440         printPacket("writePacket:", b);
441 
442         /*
443          * Check the packet size
444          */
445         if (b.length < 11) {
446             throw new IllegalArgumentException
447                 ("##> CreateVM002_Connection: writePacket() - packet is insufficient size: N1");
448         }
449         int b0 = b[0] & 0xff;
450         int b1 = b[1] & 0xff;
451         int b2 = b[2] & 0xff;
452         int b3 = b[3] & 0xff;
453         int len = ((b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << 0));
454         if (len < 11) {
455             throw new IllegalArgumentException
456                 ("##> CreateVM002_Connection: writePacket() - packet is insufficient size: N2");
457         }
458 
459         /*
460          * Check that the byte array contains the complete packet
461          */
462         if (len > b.length) {
463             throw new IllegalArgumentException
464                 ("##> CreateVM002_Connection: writePacket() - length mis-match");
465         }
466 
467         synchronized (sendLock) {
468             try {
469                 /*
470                  * Send the packet (ignoring any bytes that follow
471                  * the packet in the byte array).
472                  */
473                 socketOutput.write(b, 0, len);
474             } catch (IOException ioe) {
475                 if (!isOpen()) {
476                     throw new ClosedConnectionException
477                         ("##> CreateVM002_Connection: writePacket() - connection is closed: N2");
478                 } else {
479                     throw ioe;
480                 }
481             }
482         }
483     }
484 
toPrintPacket(boolean toPrint)485     public void toPrintPacket(boolean toPrint) {
486 
487         if ( toPrintPacket ) {
488             if ( ! toPrint ) {
489                 toPrintPacket = false;
490                 System.out.println("\n>>>> CreateVM002_Connection: toPrintPacket - Off! "
491                     + currentDateWithMlsecs());
492             }
493         } else {
494             if ( toPrint ) {
495                 toPrintPacket = true;
496                 System.out.println("\n>>>> CreateVM002_Connection: toPrintPacket - On! "
497                     + currentDateWithMlsecs());
498             }
499         }
500 
501     }
502 
currentDateWithMlsecs()503     String currentDateWithMlsecs() {
504         GregorianCalendar calendar = new GregorianCalendar();
505         int year = calendar.get(Calendar.YEAR);
506         int month = calendar.get(Calendar.MONTH) + 1;
507         String strMonth = month > 9 ? "" + month : "0" + month;
508         int day = calendar.get(Calendar.DAY_OF_MONTH);
509         String strDay = day > 9 ? "" + day : "0" + day;
510         int hours = calendar.get(Calendar.HOUR_OF_DAY);
511         String strHours = hours > 9 ? "" + hours : "0" + hours;
512         int minutes = calendar.get(Calendar.MINUTE);
513         String strMinutes = minutes > 9 ? "" + minutes : "0" + minutes;
514         int seconds = calendar.get(Calendar.SECOND);
515         String strSeconds = seconds > 9 ? "" + seconds : "0" + seconds;
516         int mlsecs = (int)(calendar.getTimeInMillis() % 1000);
517         String strMlsecs = mlsecs < 10 ? "00" + mlsecs : (mlsecs < 100 ? "0" + mlsecs : "" + mlsecs);
518         return "" + year + "." + strMonth + "." + strDay + "; " + strHours
519             + ":" + strMinutes + ":" + strSeconds + "::" + strMlsecs;
520     }
521 
522     public void printPacket(String headMessage, byte b[]) {
523 
524         if ( ! toPrintPacket ) {
525             return;
526         }
527 
528         System.out.println("\n>>>> CreateVM005_Connection: printPacket: " + currentDateWithMlsecs());
529         System.out.println("  >> " + headMessage);
530         int  packetLength = b.length;
531 
532         String handsHake = "JDWP-Handshake";
533 
534         System.out.println("  >> packet length = " + packetLength);
535         if ( packetLength < 11 ) {
536             System.out.println("  >> Invalid packet length!");
537             System.out.println("\n>>>> CreateVM005_Connection: printPacket - END\n");
538             return;
539         }
540 
541         String packetString = new String(b);
542         if ( handsHake.equals(packetString) ) {
543             System.out.println("  >> Packet as String = " + packetString);
544             System.out.println("\n>>>> CreateVM005_Connection: printPacket - END\n");
545             return;
546         }
547 
548         int b0 = b[0] & 0xff;
549         int b1 = b[1] & 0xff;
550         int b2 = b[2] & 0xff;
551         int b3 = b[3] & 0xff;
552         int lengthField = ((b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << 0));
553         System.out.println("  >> lengthField = " + lengthField);
554 
555         int b4 = b[4] & 0xff;
556         int b5 = b[5] & 0xff;
557         int b6 = b[6] & 0xff;
558         int b7 = b[7] & 0xff;
559         int idField = ((b4 << 24) | (b5 << 16) | (b6 << 8) | (b7 << 0));
560         System.out.println("  >> idField(integer) = " + idField);
561 
562         int flagsField = b[8] & 0xff;
563         System.out.println("  >> flagsField(integer) = " + flagsField);
564         int replyPacket = b[8] & 0x80;
565         if (  replyPacket != 0 ) {
566             System.out.println("  >> Replay Packet:");
567             int b9 = b[9] & 0xff;
568             int b10 = b[10] & 0xff;
569             int errorCodeField = ((b9 << 8) | (b10 << 0));
570             System.out.println("  >> errorCodeField(integer) = " + errorCodeField);
571         } else {
572             System.out.println("  >> Command Packet:");
573             int commandSetField = b[9] & 0xff;
574             System.out.println("  >> commandSetField(integer) = " + commandSetField);
575             int commandField = b[10] & 0xff;
576             System.out.println("  >> commandField(integer) = " + commandField);
577         }
578 
579         if ( packetLength > 11 ) {
580             int dataLength = packetLength-11;
581             String data = "";
582             for (int i=0; i < dataLength; i++) {
583                 data = data + "," + (int)(b[11+i] & 0xff);
584             }
585             System.out.println("  >> Packet's data = " + data);
586         }
587         System.out.println(">>>> CreateVM005_Connection: printPacket - END");
588     }
589 
590 } // end of CreateVM002_Connection class
591 
592 /*
593  * The capabilities of the socket transport service
594  */
595 class CreateVM002_TranspServCapabilities extends TransportService.Capabilities {
596 
597     public boolean supportsMultipleConnections() {
598         return true;
599     }
600 
601     public boolean supportsAttachTimeout() {
602         return true;
603     }
604 
605     public boolean supportsAcceptTimeout() {
606         return true;
607     }
608 
609     public boolean supportsHandshakeTimeout() {
610         return true;
611     }
612 
613 } // end of CreateVM002_TranspServCapabilities class
614