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 
37 import org.apache.harmony.jpda.tests.framework.DebuggeeSynchronizer;
38 import org.apache.harmony.jpda.tests.framework.LogWriter;
39 import org.apache.harmony.jpda.tests.framework.TestErrorException;
40 import org.apache.harmony.jpda.tests.framework.TestOptions;
41 
42 /**
43  * This class implements <code>DebuggeeSynchronizer</code> interface using
44  * TCP/IP sockets. All operations can be timed out according to default timeout.
45  */
46 public class JPDADebuggeeSynchronizer implements DebuggeeSynchronizer {
47 
48     public final static String SGNL_READY = "ready";
49 
50     public final static String SGNL_CONTINUE = "continue";
51 
52     protected Socket clientSocket = null;
53 
54     protected ServerSocket serverSocket = null;
55 
56     protected DataOutputStream out;
57 
58     protected DataInputStream in;
59 
60     protected TestOptions settings;
61 
62     protected LogWriter logWriter;
63 
64     /**
65      * A constructor that initializes an instance of the class with specified
66      * <code>LogWriter</code> and <code>TestOptions</code>.
67      *
68      * @param logWriter
69      *            The instance of implementation of LogWriter.
70      * @param settings
71      *            Instance of test options.
72      */
JPDADebuggeeSynchronizer(LogWriter logWriter, TestOptions settings)73     public JPDADebuggeeSynchronizer(LogWriter logWriter, TestOptions settings) {
74         super();
75         this.logWriter = logWriter;
76         this.settings = settings;
77     }
78 
79     /**
80      * Sends specified message to synchronization channel.
81      *
82      * @param message
83      *            a message to be sent.
84      */
sendMessage(String message)85     public synchronized void sendMessage(String message) {
86         try {
87             out.writeUTF(message);
88             out.flush();
89             logWriter.println("[SYNC] Message sent: " + message);
90         } catch (IOException e) {
91             throw new TestErrorException(e);
92         }
93     }
94 
95     /**
96      * Receives message from synchronization channel and compares it with the
97      * expected <code>message</code>.
98      *
99      * @param message
100      *            expected message.
101      * @return <code>true</code> if received string is equals to
102      *         <code>message</code> otherwise - <code>false</code>.
103      *
104      */
receiveMessage(String message)105     public synchronized boolean receiveMessage(String message) {
106         String msg;
107         try {
108             logWriter.println("[SYNC] Waiting for message: " + message);
109             msg = in.readUTF();
110             logWriter.println("[SYNC] Received message: " + msg);
111         } catch (EOFException e) {
112             return false;
113         } catch (IOException e) {
114             logWriter.printError(e);
115             return false;
116         }
117         return message.equalsIgnoreCase(msg);
118     }
119 
120     /**
121      * Receives message from synchronization channel.
122      *
123      * @return received string or null if connection was closed.
124      */
receiveMessage()125     public synchronized String receiveMessage() {
126         String msg;
127         try {
128             logWriter.println("[SYNC] Waiting for any messsage");
129             msg = in.readUTF();
130             logWriter.println("[SYNC] Received message: " + msg);
131         } catch (EOFException e) {
132             return null;
133         } catch (IOException e) {
134             throw new TestErrorException(e);
135         }
136         return msg;
137     }
138 
139     /**
140      * Receives message from synchronization channel without Exception.
141      *
142      * @return received string
143      */
receiveMessageWithoutException(String invoker)144     public synchronized String receiveMessageWithoutException(String invoker) {
145         String msg;
146         try {
147             logWriter.println("[SYNC] Waiting for any message");
148             msg = in.readUTF();
149             logWriter.println("[SYNC] Received message: " + msg);
150         } catch (Throwable thrown) {
151             if (invoker != null) {
152                 logWriter.println("#### receiveMessageWithoutException: Exception occurred:");
153                 logWriter.println("#### " + thrown);
154                 logWriter.println("#### Invoker = " + invoker);
155             }
156             msg = "" + thrown;
157         }
158         return msg;
159     }
160 
161     /**
162      * Returns socket address for connecting to the server.
163      *
164      * @return socket address
165      */
getSyncServerAddress()166     public InetSocketAddress getSyncServerAddress() {
167         // Use the LOOPBACK directly instead of doing a DNS lookup.
168         int port = settings.getSyncPortNumber();
169         return new InetSocketAddress(InetAddress.getLoopbackAddress(), port);
170     }
171 
172     /**
173      * Binds server to listen socket port.
174      *
175      * @return port number
176      */
bindServer()177     public synchronized int bindServer() {
178         InetSocketAddress serverAddress = getSyncServerAddress();
179         try {
180             logWriter.println("[SYNC] Binding socket on: " + serverAddress);
181             serverSocket = new ServerSocket(serverAddress.getPort(), 0, serverAddress.getAddress());
182             logWriter.println("[SYNC] Bound socket on: " + serverAddress);
183             return serverAddress.getPort();
184         } catch (IOException e) {
185             throw new TestErrorException(
186                     "[SYNC] Exception in binding for socket sync connection", e);
187         }
188     }
189 
190     /**
191      * Accepts sync connection form server side.
192      */
startServer()193     public synchronized void startServer() {
194         long timeout = settings.getTimeout();
195         try {
196             serverSocket.setSoTimeout((int) timeout);
197             logWriter.println("[SYNC] Accepting socket connection");
198             clientSocket = serverSocket.accept();
199             logWriter.println("[SYNC] Accepted socket connection");
200 
201             clientSocket.setSoTimeout((int) timeout);
202             out = new DataOutputStream(clientSocket.getOutputStream());
203             in = new DataInputStream(clientSocket.getInputStream());
204         } catch (IOException e) {
205             throw new TestErrorException(
206                     "[SYNC] Exception in accepting socket sync connection", e);
207         }
208     }
209 
210     /**
211      * Attaches for sync connection from client side..
212      */
startClient()213     public synchronized void startClient() {
214         long timeout = settings.getTimeout();
215         InetSocketAddress serverAddress = getSyncServerAddress();
216         try {
217             logWriter.println("[SYNC] Attaching socket to: " + serverAddress);
218             clientSocket = new Socket(serverAddress.getAddress(), serverAddress.getPort());
219             logWriter.println("[SYNC] Attached socket");
220 
221             clientSocket.setSoTimeout((int) timeout);
222             out = new DataOutputStream(clientSocket.getOutputStream());
223             in = new DataInputStream(clientSocket.getInputStream());
224         } catch (IOException e) {
225             throw new TestErrorException(
226                     "[SYNC] Exception in attaching for socket sync connection", e);
227         }
228     }
229 
230     /**
231      * Stops synchronization work. It ignores <code>IOException</code> but
232      * prints a message.
233      */
stop()234     public void stop() {
235         try {
236             if (out != null)
237                 out.close();
238             if (in != null)
239                 in.close();
240             if (clientSocket != null)
241                 clientSocket.close();
242             if (serverSocket != null)
243                 serverSocket.close();
244         } catch (IOException e) {
245             logWriter.println
246                     ("[SYNC] Ignoring exception in closing socket sync connection: " + e);
247         }
248         logWriter.println("[SYNC] Closed socket");
249     }
250 }
251