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 org.eclipse.jdi.internal.connect;
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 com.sun.jdi.connect.spi.ClosedConnectionException;
24 import com.sun.jdi.connect.spi.Connection;
25 
26 public class SocketConnection extends Connection {
27 
28 	// for attaching connector
29 	private Socket fSocket;
30 
31 	private InputStream fInput;
32 
33 	private OutputStream fOutput;
34 
SocketConnection(Socket socket, InputStream in, OutputStream out)35 	SocketConnection(Socket socket, InputStream in, OutputStream out) {
36 		fSocket = socket;
37 		fInput = in;
38 		fOutput = out;
39 	}
40 
41 	/*
42 	 * (non-Javadoc)
43 	 *
44 	 * @see com.sun.jdi.connect.spi.Connection#close()
45 	 */
46 	@Override
close()47 	public synchronized void close() throws IOException {
48 		if (fSocket == null)
49 			return;
50 
51 		fSocket.close();
52 		fSocket = null;
53 	}
54 
55 	/*
56 	 * (non-Javadoc)
57 	 *
58 	 * @see com.sun.jdi.connect.spi.Connection#isOpen()
59 	 */
60 	@Override
isOpen()61 	public synchronized boolean isOpen() {
62 		return fSocket != null;
63 	}
64 
65 	/*
66 	 * (non-Javadoc)
67 	 *
68 	 * @see com.sun.jdi.connect.spi.Connection#readPacket()
69 	 */
70 	@Override
readPacket()71 	public byte[] readPacket() throws IOException {
72 		DataInputStream stream;
73 		synchronized (this) {
74 			if (!isOpen()) {
75 				throw new ClosedConnectionException();
76 			}
77 			stream = new DataInputStream(fInput);
78 		}
79 		synchronized (stream) {
80 			int packetLength = 0;
81 			try {
82 				packetLength = stream.readInt();
83 			} catch (IOException e) {
84 				throw new ClosedConnectionException();
85 			}
86 
87 			if (packetLength < 11) {
88 				throw new IOException("JDWP Packet under 11 bytes"); //$NON-NLS-1$
89 			}
90 
91 			byte[] packet = new byte[packetLength];
92 			packet[0] = (byte) ((packetLength >>> 24) & 0xFF);
93 			packet[1] = (byte) ((packetLength >>> 16) & 0xFF);
94 			packet[2] = (byte) ((packetLength >>> 8) & 0xFF);
95 			packet[3] = (byte) ((packetLength >>> 0) & 0xFF);
96 
97 			stream.readFully(packet, 4, packetLength - 4);
98 			return packet;
99 		}
100 	}
101 
102 	/*
103 	 * (non-Javadoc)
104 	 *
105 	 * @see com.sun.jdi.connect.spi.Connection#writePacket(byte[])
106 	 */
107 	@Override
writePacket(byte[] packet)108 	public void writePacket(byte[] packet) throws IOException {
109 		if (!isOpen()) {
110 			throw new ClosedConnectionException();
111 		}
112 		if (packet == null) {
113 			throw new IllegalArgumentException(
114 					"Invalid JDWP Packet, packet cannot be null"); //$NON-NLS-1$
115 		}
116 		if (packet.length < 11) {
117 			throw new IllegalArgumentException(
118 					"Invalid JDWP Packet, must be at least 11 bytes. PacketSize:" + packet.length); //$NON-NLS-1$
119 		}
120 
121 		int packetSize = getPacketLength(packet);
122 		if (packetSize < 11) {
123 			throw new IllegalArgumentException(
124 					"Invalid JDWP Packet, must be at least 11 bytes. PacketSize:" + packetSize); //$NON-NLS-1$
125 		}
126 
127 		if (packetSize > packet.length) {
128 			throw new IllegalArgumentException(
129 					"Invalid JDWP packet: Specified length is greater than actual length"); //$NON-NLS-1$
130 		}
131 
132 		OutputStream stream = null;
133 		synchronized (this) {
134 			if (!isOpen()) {
135 				throw new ClosedConnectionException();
136 			}
137 			stream = fOutput;
138 		}
139 
140 		synchronized (stream) {
141 			// packet.length can be > packetSize. Sending too much will cause
142 			// errors on the other side
143 			stream.write(packet, 0, packetSize);
144 		}
145 	}
146 
getPacketLength(byte[] packet)147 	private int getPacketLength(byte[] packet) {
148 		int len = 0;
149 		if (packet.length >= 4) {
150 			len = (((packet[0] & 0xFF) << 24) + ((packet[1] & 0xFF) << 16)
151 					+ ((packet[2] & 0xFF) << 8) + ((packet[3] & 0xFF) << 0));
152 		}
153 		return len;
154 	}
155 }
156