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 */ 86 @Override sendMessage(String message)87 public synchronized void sendMessage(String message) { 88 try { 89 out.writeUTF(message); 90 out.flush(); 91 logWriter.println("[SYNC] Message sent: " + message); 92 } catch (IOException e) { 93 throw new TestErrorException(e); 94 } 95 } 96 97 /** 98 * Receives message from synchronization channel and compares it with the 99 * expected <code>message</code>. 100 * 101 * @param message 102 * expected message. 103 * @return <code>true</code> if received string is equals to 104 * <code>message</code> otherwise - <code>false</code>. 105 * 106 */ 107 @Override receiveMessage(String message)108 public synchronized boolean receiveMessage(String message) { 109 String msg; 110 try { 111 logWriter.println("[SYNC] Waiting for message: " + message); 112 msg = in.readUTF(); 113 logWriter.println("[SYNC] Received message: " + msg); 114 } catch (EOFException e) { 115 return false; 116 } catch (IOException e) { 117 logWriter.printError(e); 118 return false; 119 } 120 return message.equalsIgnoreCase(msg); 121 } 122 123 /** 124 * Receives message from synchronization channel. 125 * 126 * @return received string or null if connection was closed. 127 */ 128 @Override receiveMessage()129 public synchronized String receiveMessage() { 130 String msg; 131 try { 132 logWriter.println("[SYNC] Waiting for any messsage"); 133 msg = in.readUTF(); 134 logWriter.println("[SYNC] Received message: " + msg); 135 } catch (EOFException e) { 136 return null; 137 } catch (IOException e) { 138 throw new TestErrorException(e); 139 } 140 return msg; 141 } 142 143 /** 144 * Receives message from synchronization channel without Exception. 145 * 146 * @return received string 147 */ receiveMessageWithoutException(String invoker)148 public synchronized String receiveMessageWithoutException(String invoker) { 149 String msg; 150 try { 151 logWriter.println("[SYNC] Waiting for any message"); 152 msg = in.readUTF(); 153 logWriter.println("[SYNC] Received message: " + msg); 154 } catch (Throwable thrown) { 155 if (invoker != null) { 156 logWriter.println("#### receiveMessageWithoutException: Exception occurred:"); 157 logWriter.println("#### " + thrown); 158 logWriter.println("#### Invoker = " + invoker); 159 } 160 msg = "" + thrown; 161 } 162 return msg; 163 } 164 165 /** 166 * Returns socket address for connecting to the server. 167 * 168 * If <code>serverAddress.getPort()</code> returns 0 (i.e., 169 * <code>org.apache.harmony.jpda.tests.framework.TestOptions.DEFAULT_SYNC_PORT</code>), 170 * a port will automatically be chosen by the OS when the server is bound to a socket. 171 * 172 * @return socket address 173 */ getSyncServerAddress()174 public InetSocketAddress getSyncServerAddress() { 175 // Use the LOOPBACK directly instead of doing a DNS lookup. 176 int port = settings.getSyncPortNumber(); 177 try { 178 // Use IPv4 to ensure we do not depend on IPv6 to run these tests. 179 // TODO(25178637): Use InetAddress.getLoopbackAddress() instead. 180 return new InetSocketAddress( 181 InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }), port); 182 } catch (UnknownHostException e) { 183 throw new TestErrorException( 184 "[SYNC] Exception in binding for socket sync connection", e); 185 } 186 } 187 188 /** 189 * Binds server to listen socket port. 190 * 191 * If <code>serverAddress.getPort()</code> returns 0 (i.e., 192 * <code>org.apache.harmony.jpda.tests.framework.TestOptions.DEFAULT_SYNC_PORT</code>), 193 * the OS will choose a port automatically for this server socket. 194 * 195 * @return port number 196 */ bindServer()197 public synchronized int bindServer() { 198 InetSocketAddress serverAddress = getSyncServerAddress(); 199 try { 200 logWriter.println("[SYNC] Binding socket on: " + serverAddress); 201 serverSocket = new ServerSocket(serverAddress.getPort(), 0, serverAddress.getAddress()); 202 int localPort = serverSocket.getLocalPort(); 203 logWriter.println("[SYNC] Bound socket on: " + serverAddress 204 + " (local port: " + localPort + ")" ); 205 return localPort; 206 } catch (IOException e) { 207 throw new TestErrorException( 208 "[SYNC] Exception in binding for socket sync connection", e); 209 } 210 } 211 212 /** 213 * Accepts sync connection form server side. 214 */ startServer()215 public synchronized void startServer() { 216 long timeout = settings.getTimeout(); 217 try { 218 serverSocket.setSoTimeout((int) timeout); 219 logWriter.println("[SYNC] Accepting socket connection"); 220 clientSocket = serverSocket.accept(); 221 logWriter.println("[SYNC] Accepted socket connection"); 222 223 clientSocket.setSoTimeout((int) timeout); 224 out = new DataOutputStream(clientSocket.getOutputStream()); 225 in = new DataInputStream(clientSocket.getInputStream()); 226 } catch (IOException e) { 227 throw new TestErrorException( 228 "[SYNC] Exception in accepting socket sync connection", e); 229 } 230 } 231 232 /** 233 * Attaches for sync connection from client side.. 234 */ startClient()235 public synchronized void startClient() { 236 long timeout = settings.getTimeout(); 237 InetSocketAddress serverAddress = getSyncServerAddress(); 238 try { 239 logWriter.println("[SYNC] Attaching socket to: " + serverAddress); 240 clientSocket = new Socket(serverAddress.getAddress(), serverAddress.getPort()); 241 logWriter.println("[SYNC] Attached socket"); 242 243 clientSocket.setSoTimeout((int) timeout); 244 out = new DataOutputStream(clientSocket.getOutputStream()); 245 in = new DataInputStream(clientSocket.getInputStream()); 246 } catch (IOException e) { 247 throw new TestErrorException( 248 "[SYNC] Exception in attaching for socket sync connection", e); 249 } 250 } 251 252 /** 253 * Stops synchronization work. It ignores <code>IOException</code> but 254 * prints a message. 255 */ stop()256 public void stop() { 257 try { 258 if (out != null) 259 out.close(); 260 if (in != null) 261 in.close(); 262 if (clientSocket != null) 263 clientSocket.close(); 264 if (serverSocket != null) 265 serverSocket.close(); 266 } catch (IOException e) { 267 logWriter.println 268 ("[SYNC] Ignoring exception in closing socket sync connection: " + e); 269 } 270 logWriter.println("[SYNC] Closed socket"); 271 } 272 } 273