blob: 4ebf6840db3d5cf603a645dadb073028d0c6949d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Vitaly A. Provodin
*/
/**
* Created on 29.01.2005
*/
package org.apache.harmony.jpda.tests.share;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import org.apache.harmony.jpda.tests.framework.DebuggeeSynchronizer;
import org.apache.harmony.jpda.tests.framework.LogWriter;
import org.apache.harmony.jpda.tests.framework.TestErrorException;
import org.apache.harmony.jpda.tests.framework.TestOptions;
/**
* This class implements <code>DebuggeeSynchronizer</code> interface using
* TCP/IP sockets. All operations can be timed out according to default timeout.
*/
public class JPDADebuggeeSynchronizer implements DebuggeeSynchronizer {
public final static String SGNL_READY = "ready";
public final static String SGNL_CONTINUE = "continue";
protected Socket clientSocket = null;
protected ServerSocket serverSocket = null;
protected DataOutputStream out;
protected DataInputStream in;
protected TestOptions settings;
protected LogWriter logWriter;
/**
* A constructor that initializes an instance of the class with specified
* <code>LogWriter</code> and <code>TestOptions</code>.
*
* @param logWriter
* The instance of implementation of LogWriter.
* @param settings
* Instance of test options.
*/
public JPDADebuggeeSynchronizer(LogWriter logWriter, TestOptions settings) {
super();
this.logWriter = logWriter;
this.settings = settings;
}
/**
* Sends specified message to synchronization channel.
*
* @param message
* a message to be sent.
*/
public synchronized void sendMessage(String message) {
try {
out.writeUTF(message);
out.flush();
logWriter.println("[SYNC] Message sent: " + message);
} catch (IOException e) {
throw new TestErrorException(e);
}
}
/**
* Receives message from synchronization channel and compares it with the
* expected <code>message</code>.
*
* @param message
* expected message.
* @return <code>true</code> if received string is equals to
* <code>message</code> otherwise - <code>false</code>.
*
*/
public synchronized boolean receiveMessage(String message) {
String msg;
try {
logWriter.println("[SYNC] Waiting for message: " + message);
msg = in.readUTF();
logWriter.println("[SYNC] Received message: " + msg);
} catch (EOFException e) {
return false;
} catch (IOException e) {
logWriter.printError(e);
return false;
}
return message.equalsIgnoreCase(msg);
}
/**
* Receives message from synchronization channel.
*
* @return received string or null if connection was closed.
*/
public synchronized String receiveMessage() {
String msg;
try {
logWriter.println("[SYNC] Waiting for any messsage");
msg = in.readUTF();
logWriter.println("[SYNC] Received message: " + msg);
} catch (EOFException e) {
return null;
} catch (IOException e) {
throw new TestErrorException(e);
}
return msg;
}
/**
* Receives message from synchronization channel without Exception.
*
* @return received string
*/
public synchronized String receiveMessageWithoutException(String invoker) {
String msg;
try {
logWriter.println("[SYNC] Waiting for any message");
msg = in.readUTF();
logWriter.println("[SYNC] Received message: " + msg);
} catch (Throwable thrown) {
if (invoker != null) {
logWriter.println("#### receiveMessageWithoutException: Exception occurred:");
logWriter.println("#### " + thrown);
logWriter.println("#### Invoker = " + invoker);
}
msg = "" + thrown;
}
return msg;
}
/**
* Returns socket address for connecting to the server.
*
* If <code>serverAddress.getPort()</code> returns 0 (i.e.,
* <code>org.apache.harmony.jpda.tests.framework.TestOptions.DEFAULT_SYNC_PORT</code>),
* a port will automatically be chosen by the OS when the server is bound to a socket.
*
* @return socket address
*/
public InetSocketAddress getSyncServerAddress() {
// Use the LOOPBACK directly instead of doing a DNS lookup.
int port = settings.getSyncPortNumber();
try {
// Use IPv4 to ensure we do not depend on IPv6 to run these tests.
// TODO(25178637): Use InetAddress.getLoopbackAddress() instead.
return new InetSocketAddress(
InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }), port);
} catch (UnknownHostException e) {
throw new TestErrorException(
"[SYNC] Exception in binding for socket sync connection", e);
}
}
/**
* Binds server to listen socket port.
*
* If <code>serverAddress.getPort()</code> returns 0 (i.e.,
* <code>org.apache.harmony.jpda.tests.framework.TestOptions.DEFAULT_SYNC_PORT</code>),
* the OS will choose a port automatically for this server socket.
*
* @return port number
*/
public synchronized int bindServer() {
InetSocketAddress serverAddress = getSyncServerAddress();
try {
logWriter.println("[SYNC] Binding socket on: " + serverAddress);
serverSocket = new ServerSocket(serverAddress.getPort(), 0, serverAddress.getAddress());
int localPort = serverSocket.getLocalPort();
logWriter.println("[SYNC] Bound socket on: " + serverAddress
+ " (local port: " + localPort + ")" );
return localPort;
} catch (IOException e) {
throw new TestErrorException(
"[SYNC] Exception in binding for socket sync connection", e);
}
}
/**
* Accepts sync connection form server side.
*/
public synchronized void startServer() {
long timeout = settings.getTimeout();
try {
serverSocket.setSoTimeout((int) timeout);
logWriter.println("[SYNC] Accepting socket connection");
clientSocket = serverSocket.accept();
logWriter.println("[SYNC] Accepted socket connection");
clientSocket.setSoTimeout((int) timeout);
out = new DataOutputStream(clientSocket.getOutputStream());
in = new DataInputStream(clientSocket.getInputStream());
} catch (IOException e) {
throw new TestErrorException(
"[SYNC] Exception in accepting socket sync connection", e);
}
}
/**
* Attaches for sync connection from client side..
*/
public synchronized void startClient() {
long timeout = settings.getTimeout();
InetSocketAddress serverAddress = getSyncServerAddress();
try {
logWriter.println("[SYNC] Attaching socket to: " + serverAddress);
clientSocket = new Socket(serverAddress.getAddress(), serverAddress.getPort());
logWriter.println("[SYNC] Attached socket");
clientSocket.setSoTimeout((int) timeout);
out = new DataOutputStream(clientSocket.getOutputStream());
in = new DataInputStream(clientSocket.getInputStream());
} catch (IOException e) {
throw new TestErrorException(
"[SYNC] Exception in attaching for socket sync connection", e);
}
}
/**
* Stops synchronization work. It ignores <code>IOException</code> but
* prints a message.
*/
public void stop() {
try {
if (out != null)
out.close();
if (in != null)
in.close();
if (clientSocket != null)
clientSocket.close();
if (serverSocket != null)
serverSocket.close();
} catch (IOException e) {
logWriter.println
("[SYNC] Ignoring exception in closing socket sync connection: " + e);
}
logWriter.println("[SYNC] Closed socket");
}
}