blob: 72eb1005ce80699b2bc43ffb1fe21af6ac2f38a0 [file] [log] [blame]
/*
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package nsk.share.jdwp;
import nsk.share.*;
import java.io.*;
import java.net.*;
/**
* This class represents a socket transport for JDWP.
*/
public class SocketTransport extends Transport {
/**
* Socket for established JDWP connection.
*/
private Socket socket = null;
/**
* ServerSocket for listening JDWP connection.
*/
private ServerSocket serverSocket = null;
/**
* Input stream of socket.
*/
private InputStream in = null;
/**
* Output stream of socket.
*/
private OutputStream out = null;
/**
* Port to listen to.
*/
int listenPort = 0;
/**
* Make <code>SocketTransport</cose> object with providing specified Log.
*/
public SocketTransport(Log log) {
super(log);
}
/**
* Bind for connection from target VM to specified port number.
* If given port number is 0 then bind to any free port number.
*
* @return port number which this transport is listening for
*/
public int bind(int port)
throws IOException {
serverSocket = new ServerSocket();
if (port == 0) {
// Only need SO_REUSEADDR if we're using a fixed port. If we
// start seeing EADDRINUSE due to collisions in free ports
// then we should retry the bind() a few times.
display("port == 0, disabling SO_REUSEADDR");
serverSocket.setReuseAddress(false);
}
serverSocket.bind(new InetSocketAddress(port));
listenPort = serverSocket.getLocalPort();
return listenPort;
}
/**
* Attach to the target VM for specified host name and port number.
*/
public void attach(String ServerName, int PortNumber)
throws UnknownHostException, IOException {
for (int i = 0; i < Binder.CONNECT_TRIES; i++ ) {
try {
socket = new Socket(ServerName, PortNumber);
display("JDWP socket connection established");
// socket.setTcpNoDelay(true);
in = socket.getInputStream();
out = socket.getOutputStream();
return;
} catch (IOException e) {
display("Attempt #" + i + " to establish JDWP socket connection failed:\n\t" + e);
try {
Thread.currentThread().sleep(Binder.CONNECT_TRY_DELAY);
} catch (InterruptedException ie) {
ie.printStackTrace(log.getOutStream());
throw new Failure("Thread interrupted while establishing JDWP connection: \n\t"
+ ie);
}
}
}
throw new IOException("Timeout exceeded while establishing JDWP socket connection to "
+ ServerName + ":" + PortNumber);
}
/**
* Accept connection from target VM for already boud port.
*/
public void accept()
throws IOException {
if (serverSocket == null)
throw new Failure("Attempt to accept JDWP socket connection from unbound port");
socket = serverSocket.accept();
serverSocket.close();
serverSocket = null;
in = socket.getInputStream();
out = socket.getOutputStream();
}
/**
* Close socket and streams.
*/
public void close() throws IOException {
if (socket == null)
return;
if (out != null) {
flush();
out.close();
}
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
socket = null;
}
if (serverSocket != null) {
serverSocket.close();
serverSocket = null;
}
}
/**
* Return number of bytes that can be read.
*/
public int available() throws IOException {
return in.available();
};
/**
* Flush bytes being buffered for writing if any.
*/
public void flush() throws IOException {
out.flush();
}
/**
* Set timeout for reading data in milliseconds.
*/
public void setReadTimeout(long millisecs) throws IOException {
socket.setSoTimeout((int)millisecs);
}
/**
* Read the next byte of data from the socket.
* The value byte is returned as an int in the range 0 to 255.
* If no byte is available, the value -1 is returned.
*/
public byte read() throws IOException {
int b = in.read();
if (b < 0) {
throw new IOException("JDWP socket connection closed by remote host");
}
return (byte) b;
};
/**
* Write the specified byte to the socket.
*/
public void write(int b) throws IOException {
out.write(b);
};
}