Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketIOPipe.java
41161 views
/*1* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/22package nsk.share.jpda;2324import java.io.IOException;25import java.net.InetSocketAddress;26import java.net.ServerSocket;27import nsk.share.*;2829/*30* This class represents communication channel based on TCP/IP sockets.31* Usage of this class implies creation of objects of 2 types: server SocketIOPipe object32* (this object creates server socket and waits for incoming connection) and client33* SocketIOPipe (this object attaches to server).34*35* Server and client objects should be created using special static methods provided by this class,36* for example 'createServerIOPipe(Log log, int port, long timeout)' for server SocketIOPipe37* and 'createClientIOPipe(Log log, String host, int port, long timeout)' for client SocketIOPipe.38*39* When SocketIOPipe is created it can be used to send and receive strings using methods 'readln()' and 'println(String s)'.40* TCP/IP connection is established at the first attempt to read or write data.41*42* For example, if client process should send string 'OK' to the server process which is run43* at the host 'SERVER_HOST' following code can be written:44*45* Server side:46*47* // SocketIOPipe creates ServerSocket listening given port48* SocketIOPipe pipe = SocketIOPipe.createServerIOPipe(log, port, timeoutValue);49*50* // SocketIOPipe waits connection from client and reads data sent by the client51* String command = pipe.readln();52*53* Client side:54*55* // initialize SocketIOPipe with given values of server host name and port56* SocketIOPipe pipe = SocketIOPipe.createClientIOPipe(log, 'SERVER_HOST', port, timeoutValue);57*58* String command = "OK";59* // SocketIOPipe tries to create socket and send command to the server60* pipe.println(command);61*62*/63public class SocketIOPipe extends Log.Logger implements Finalizable {6465public static final int DEFAULT_TIMEOUT_VALUE = 1 * 60 * 1000;6667public static final String DEFAULT_PIPE_LOG_PREFIX = "SocketIOPipe> ";6869protected boolean listening;7071protected String host;7273protected int port;7475protected long timeout;7677protected SocketConnection connection;7879protected volatile boolean shouldStop;8081protected Process connectingProcess;8283protected ServerSocket serverSocket;8485protected String name;8687/**88* Make general <code>IOPipe</code> object with specified parameters.89*/90protected SocketIOPipe(String name, Log log, String logPrefix, String host, int port, long timeout, boolean listening) {91super(log, logPrefix);92this.host = host;93this.port = port;94this.timeout = timeout;95this.listening = listening;96this.name = name;97}9899/**100* Make general <code>IOPipe</code> object with specified parameters.101*/102protected SocketIOPipe(Log log, String logPrefix, String host, int port, long timeout, boolean listening) {103super(log, logPrefix);104this.host = host;105this.port = port;106this.timeout = timeout;107this.listening = listening;108}109110/**111* Create listening SocketIOPipe using given port112*/113public static SocketIOPipe createServerIOPipe(Log log, int port, long timeout) {114SocketIOPipe pipe = new SocketIOPipe(log, DEFAULT_PIPE_LOG_PREFIX, null, 0, timeout, true);115116try {117ServerSocket ss = new ServerSocket();118if (port == 0) {119// Only need SO_REUSEADDR if we're using a fixed port. If we120// start seeing EADDRINUSE due to collisions in free ports121// then we should retry the bind() a few times.122ss.setReuseAddress(false);123}124ss.bind(new InetSocketAddress(port));125pipe.setServerSocket(ss);126} catch (IOException e) {127e.printStackTrace(log.getOutStream());128throw new Failure("Caught IOException while binding for IOPipe connection: \n\t" + e);129}130131return pipe;132}133134/**135* Create listening SocketIOPipe using any free port136*/137public static SocketIOPipe createServerIOPipe(Log log, long timeout) {138return createServerIOPipe(log, 0, timeout);139}140141/**142* Create attaching SocketIOPipe using given port and timeout143*/144public static SocketIOPipe createClientIOPipe(Log log, String host, int port, long timeout) {145return new SocketIOPipe(log, DEFAULT_PIPE_LOG_PREFIX, host, port, timeout, false);146}147148/**149* Return true if <code>IOPipe</code> connection established.150*/151public boolean isConnected() {152return (connection != null && connection.isConnected());153}154155/**156* Returns port number used by SocketIOPipe157*/158public int getPort() {159return port;160}161162protected void setConnectingProcess(Process connectingProcess) {163this.connectingProcess = connectingProcess;164}165166protected void setServerSocket(ServerSocket serverSocket) {167this.serverSocket = serverSocket;168if (serverSocket != null)169port = serverSocket.getLocalPort();170}171172/**173* Write (and flush) given <code>line</code> to this174* <code>IOPipe</code> cnannel.175*176* @throws Failure if error occured while sending data177*/178public void println(String line) {179if (connection == null) {180connect();181}182connection.writeObject(line);183}184185/**186* Read a text line from this <code>IOPipe</code> channel,187* or return <i>null</i> if EOF reached.188*189* @throws Failure if error occured while reading data190*/191public String readln() {192if (connection == null) {193connect();194}195String line = (String) connection.readObject();196return line;197}198199/**200* Close this <code>IOPipe</code> connection.201*/202public void close() {203shouldStop = true;204if (connection != null) {205connection.close();206}207}208209/**210* Establish <code>IOPipe</code> connection by attaching or accepting211* connection appropriately.212*/213protected void connect() {214if (connection != null) {215throw new TestBug("IOPipe connection is already established");216}217218if (shouldStop)219return;220221connection = new SocketConnection(this, getName());222223if (listening) {224connection.setConnectingProcess(connectingProcess);225if (serverSocket == null) {226connection.bind(port, timeout);227} else {228connection.setServerSocket(serverSocket);229}230231if (shouldStop)232return;233234// wait for connection from remote host235connection.accept(timeout);236237} else {238// attach from the debuggee's side239connection.continueAttach(host, port, timeout);240}241}242243/**244* Set ping timeout in milliseconds (0 means don't use ping at all).245*/246public void setPingTimeout(long timeout) {247if (connection == null) {248throw new TestBug("Attempt to set ping timeout for not established connection");249}250connection.setPingTimeout(timeout);251}252253/**254* Returns value of current ping timeout in milliseconds (0 means ping is not used).255*/256public long getPingTimeout() {257if (connection == null) {258throw new TestBug("Attempt to get ping timeout for not established connection");259}260return connection.getPingTimeout();261}262263/**264* Perform finalization of the object by invoking close().265*/266protected void finalize() throws Throwable {267close();268super.finalize();269}270271/**272* Perform finalization of the object at exit by invoking finalize().273*/274public void finalizeAtExit() throws Throwable {275finalize();276}277278/**279* Field 'pipeCounter' and method 'getNextPipeNumber' are used to construct unique names for SocketIOPipes280*/281private static int pipeCounter;282283private synchronized int getNextPipeNumber() {284return pipeCounter++;285}286287/**288* Construct name for SocketIOPipe if it wasn't specified289*/290private String getName() {291if (name == null) {292name = "SocketIOPipe-" + getNextPipeNumber();293}294295return name;296}297}298299300