1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 /** 20 * @author Vitaly A. Provodin 21 */ 22 23 /** 24 * Created on 29.01.2005 25 */ 26 package org.apache.harmony.jpda.tests.share; 27 28 import java.io.DataInputStream; 29 import java.io.DataOutputStream; 30 import java.io.EOFException; 31 import java.io.IOException; 32 import java.net.InetAddress; 33 import java.net.InetSocketAddress; 34 import java.net.Socket; 35 import java.net.ServerSocket; 36 import java.net.UnknownHostException; 37 38 import org.apache.harmony.jpda.tests.framework.DebuggeeSynchronizer; 39 import org.apache.harmony.jpda.tests.framework.LogWriter; 40 import org.apache.harmony.jpda.tests.framework.TestErrorException; 41 import org.apache.harmony.jpda.tests.framework.TestOptions; 42 43 /** 44 * This class implements <code>DebuggeeSynchronizer</code> interface using 45 * TCP/IP sockets. All operations can be timed out according to default timeout. 46 */ 47 public class JPDADebuggeeSynchronizer implements DebuggeeSynchronizer { 48 49 public final static String SGNL_READY = "ready"; 50 51 public final static String SGNL_CONTINUE = "continue"; 52 53 protected Socket clientSocket = null; 54 55 protected ServerSocket serverSocket = null; 56 57 protected DataOutputStream out; 58 59 protected DataInputStream in; 60 61 protected TestOptions settings; 62 63 protected LogWriter logWriter; 64 65 /** 66 * A constructor that initializes an instance of the class with specified 67 * <code>LogWriter</code> and <code>TestOptions</code>. 68 * 69 * @param logWriter 70 * The instance of implementation of LogWriter. 71 * @param settings 72 * Instance of test options. 73 */ JPDADebuggeeSynchronizer(LogWriter logWriter, TestOptions settings)74 public JPDADebuggeeSynchronizer(LogWriter logWriter, TestOptions settings) { 75 super(); 76 this.logWriter = logWriter; 77 this.settings = settings; 78 } 79 80 /** 81 * Sends specified message to synchronization channel. 82 * 83 * @param message 84 * a message to be sent. 85 */ sendMessage(String message)86 public synchronized void sendMessage(String message) { 87 try { 88 out.writeUTF(message); 89 out.flush(); 90 logWriter.println("[SYNC] Message sent: " + message); 91 } catch (IOException e) { 92 throw new TestErrorException(e); 93 } 94 } 95 96 /** 97 * Receives message from synchronization channel and compares it with the 98 * expected <code>message</code>. 99 * 100 * @param message 101 * expected message. 102 * @return <code>true</code> if received string is equals to 103 * <code>message</code> otherwise - <code>false</code>. 104 * 105 */ receiveMessage(String message)106 public synchronized boolean receiveMessage(String message) { 107 String msg; 108 try { 109 logWriter.println("[SYNC] Waiting for message: " + message); 110 msg = in.readUTF(); 111 logWriter.println("[SYNC] Received message: " + msg); 112 } catch (EOFException e) { 113 return false; 114 } catch (IOException e) { 115 logWriter.printError(e); 116 return false; 117 } 118 return message.equalsIgnoreCase(msg); 119 } 120 121 /** 122 * Receives message from synchronization channel. 123 * 124 * @return received string or null if connection was closed. 125 */ receiveMessage()126 public synchronized String receiveMessage() { 127 String msg; 128 try { 129 logWriter.println("[SYNC] Waiting for any messsage"); 130 msg = in.readUTF(); 131 logWriter.println("[SYNC] Received message: " + msg); 132 } catch (EOFException e) { 133 return null; 134 } catch (IOException e) { 135 throw new TestErrorException(e); 136 } 137 return msg; 138 } 139 140 /** 141 * Receives message from synchronization channel without Exception. 142 * 143 * @return received string 144 */ receiveMessageWithoutException(String invoker)145 public synchronized String receiveMessageWithoutException(String invoker) { 146 String msg; 147 try { 148 logWriter.println("[SYNC] Waiting for any message"); 149 msg = in.readUTF(); 150 logWriter.println("[SYNC] Received message: " + msg); 151 } catch (Throwable thrown) { 152 if (invoker != null) { 153 logWriter.println("#### receiveMessageWithoutException: Exception occurred:"); 154 logWriter.println("#### " + thrown); 155 logWriter.println("#### Invoker = " + invoker); 156 } 157 msg = "" + thrown; 158 } 159 return msg; 160 } 161 162 /** 163 * Returns socket address for connecting to the server. 164 * 165 * If <code>serverAddress.getPort()</code> returns 0 (i.e., 166 * <code>org.apache.harmony.jpda.tests.framework.TestOptions.DEFAULT_SYNC_PORT</code>), 167 * a port will automatically be chosen by the OS when the server is bound to a socket. 168 * 169 * @return socket address 170 */ getSyncServerAddress()171 public InetSocketAddress getSyncServerAddress() { 172 // Use the LOOPBACK directly instead of doing a DNS lookup. 173 int port = settings.getSyncPortNumber(); 174 try { 175 // Use IPv4 to ensure we do not depend on IPv6 to run these tests. 176 // TODO(25178637): Use InetAddress.getLoopbackAddress() instead. 177 return new InetSocketAddress( 178 InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }), port); 179 } catch (UnknownHostException e) { 180 throw new TestErrorException( 181 "[SYNC] Exception in binding for socket sync connection", e); 182 } 183 } 184 185 /** 186 * Binds server to listen socket port. 187 * 188 * If <code>serverAddress.getPort()</code> returns 0 (i.e., 189 * <code>org.apache.harmony.jpda.tests.framework.TestOptions.DEFAULT_SYNC_PORT</code>), 190 * the OS will choose a port automatically for this server socket. 191 * 192 * @return port number 193 */ bindServer()194 public synchronized int bindServer() { 195 InetSocketAddress serverAddress = getSyncServerAddress(); 196 try { 197 logWriter.println("[SYNC] Binding socket on: " + serverAddress); 198 serverSocket = new ServerSocket(serverAddress.getPort(), 0, serverAddress.getAddress()); 199 int localPort = serverSocket.getLocalPort(); 200 logWriter.println("[SYNC] Bound socket on: " + serverAddress 201 + " (local port: " + localPort + ")" ); 202 return localPort; 203 } catch (IOException e) { 204 throw new TestErrorException( 205 "[SYNC] Exception in binding for socket sync connection", e); 206 } 207 } 208 209 /** 210 * Accepts sync connection form server side. 211 */ startServer()212 public synchronized void startServer() { 213 long timeout = settings.getTimeout(); 214 try { 215 serverSocket.setSoTimeout((int) timeout); 216 logWriter.println("[SYNC] Accepting socket connection"); 217 clientSocket = serverSocket.accept(); 218 logWriter.println("[SYNC] Accepted socket connection"); 219 220 clientSocket.setSoTimeout((int) timeout); 221 out = new DataOutputStream(clientSocket.getOutputStream()); 222 in = new DataInputStream(clientSocket.getInputStream()); 223 } catch (IOException e) { 224 throw new TestErrorException( 225 "[SYNC] Exception in accepting socket sync connection", e); 226 } 227 } 228 229 /** 230 * Attaches for sync connection from client side.. 231 */ startClient()232 public synchronized void startClient() { 233 long timeout = settings.getTimeout(); 234 InetSocketAddress serverAddress = getSyncServerAddress(); 235 try { 236 logWriter.println("[SYNC] Attaching socket to: " + serverAddress); 237 clientSocket = new Socket(serverAddress.getAddress(), serverAddress.getPort()); 238 logWriter.println("[SYNC] Attached socket"); 239 240 clientSocket.setSoTimeout((int) timeout); 241 out = new DataOutputStream(clientSocket.getOutputStream()); 242 in = new DataInputStream(clientSocket.getInputStream()); 243 } catch (IOException e) { 244 throw new TestErrorException( 245 "[SYNC] Exception in attaching for socket sync connection", e); 246 } 247 } 248 249 /** 250 * Stops synchronization work. It ignores <code>IOException</code> but 251 * prints a message. 252 */ stop()253 public void stop() { 254 try { 255 if (out != null) 256 out.close(); 257 if (in != null) 258 in.close(); 259 if (clientSocket != null) 260 clientSocket.close(); 261 if (serverSocket != null) 262 serverSocket.close(); 263 } catch (IOException e) { 264 logWriter.println 265 ("[SYNC] Ignoring exception in closing socket sync connection: " + e); 266 } 267 logWriter.println("[SYNC] Closed socket"); 268 } 269 } 270