Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketIOPipe.java
66661 views
1
/*
2
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
package nsk.share.jpda;
24
25
import java.io.IOException;
26
import java.net.InetSocketAddress;
27
import java.net.ServerSocket;
28
import nsk.share.*;
29
30
/*
31
* This class represents communication channel based on TCP/IP sockets.
32
* Usage of this class implies creation of objects of 2 types: server SocketIOPipe object
33
* (this object creates server socket and waits for incoming connection) and client
34
* SocketIOPipe (this object attaches to server).
35
*
36
* Server and client objects should be created using special static methods provided by this class,
37
* for example 'createServerIOPipe(Log log, int port, long timeout)' for server SocketIOPipe
38
* and 'createClientIOPipe(Log log, String host, int port, long timeout)' for client SocketIOPipe.
39
*
40
* When SocketIOPipe is created it can be used to send and receive strings using methods 'readln()' and 'println(String s)'.
41
* TCP/IP connection is established at the first attempt to read or write data.
42
*
43
* For example, if client process should send string 'OK' to the server process which is run
44
* at the host 'SERVER_HOST' following code can be written:
45
*
46
* Server side:
47
*
48
* // SocketIOPipe creates ServerSocket listening given port
49
* SocketIOPipe pipe = SocketIOPipe.createServerIOPipe(log, port, timeoutValue);
50
*
51
* // SocketIOPipe waits connection from client and reads data sent by the client
52
* String command = pipe.readln();
53
*
54
* Client side:
55
*
56
* // initialize SocketIOPipe with given values of server host name and port
57
* SocketIOPipe pipe = SocketIOPipe.createClientIOPipe(log, 'SERVER_HOST', port, timeoutValue);
58
*
59
* String command = "OK";
60
* // SocketIOPipe tries to create socket and send command to the server
61
* pipe.println(command);
62
*
63
*/
64
public class SocketIOPipe extends Log.Logger implements Finalizable {
65
66
public static final int DEFAULT_TIMEOUT_VALUE = 1 * 60 * 1000;
67
68
public static final String DEFAULT_PIPE_LOG_PREFIX = "SocketIOPipe> ";
69
70
protected boolean listening;
71
72
protected String host;
73
74
protected int port;
75
76
protected long timeout;
77
78
protected SocketConnection connection;
79
80
protected volatile boolean shouldStop;
81
82
protected ServerSocket serverSocket;
83
84
protected String name;
85
86
/**
87
* Make general <code>IOPipe</code> object with specified parameters.
88
*/
89
protected SocketIOPipe(String name, Log log, String logPrefix, String host, int port, long timeout, boolean listening) {
90
super(log, logPrefix);
91
this.host = host;
92
this.port = port;
93
this.timeout = timeout;
94
this.listening = listening;
95
this.name = name;
96
}
97
98
/**
99
* Make general <code>IOPipe</code> object with specified parameters.
100
*/
101
protected SocketIOPipe(Log log, String logPrefix, String host, int port, long timeout, boolean listening) {
102
super(log, logPrefix);
103
this.host = host;
104
this.port = port;
105
this.timeout = timeout;
106
this.listening = listening;
107
}
108
109
/**
110
* Create listening SocketIOPipe using given port
111
*/
112
public static SocketIOPipe createServerIOPipe(Log log, int port, long timeout) {
113
SocketIOPipe pipe = new SocketIOPipe(log, DEFAULT_PIPE_LOG_PREFIX, null, 0, timeout, true);
114
115
try {
116
ServerSocket ss = new ServerSocket();
117
if (port == 0) {
118
// Only need SO_REUSEADDR if we're using a fixed port. If we
119
// start seeing EADDRINUSE due to collisions in free ports
120
// then we should retry the bind() a few times.
121
ss.setReuseAddress(false);
122
}
123
ss.bind(new InetSocketAddress(port));
124
pipe.setServerSocket(ss);
125
} catch (IOException e) {
126
e.printStackTrace(log.getOutStream());
127
throw new Failure("Caught IOException while binding for IOPipe connection: \n\t" + e);
128
}
129
130
return pipe;
131
}
132
133
/**
134
* Create listening SocketIOPipe using any free port
135
*/
136
public static SocketIOPipe createServerIOPipe(Log log, long timeout) {
137
return createServerIOPipe(log, 0, timeout);
138
}
139
140
/**
141
* Create attaching SocketIOPipe using given port and timeout
142
*/
143
public static SocketIOPipe createClientIOPipe(Log log, String host, int port, long timeout) {
144
return new SocketIOPipe(log, DEFAULT_PIPE_LOG_PREFIX, host, port, timeout, false);
145
}
146
147
/**
148
* Return true if <code>IOPipe</code> connection established.
149
*/
150
public boolean isConnected() {
151
return (connection != null && connection.isConnected());
152
}
153
154
/**
155
* Returns port number used by SocketIOPipe
156
*/
157
public int getPort() {
158
return port;
159
}
160
161
protected void setServerSocket(ServerSocket serverSocket) {
162
this.serverSocket = serverSocket;
163
if (serverSocket != null)
164
port = serverSocket.getLocalPort();
165
}
166
167
/**
168
* Write (and flush) given <code>line</code> to this
169
* <code>IOPipe</code> cnannel.
170
*
171
* @throws Failure if error occured while sending data
172
*/
173
public void println(String line) {
174
if (connection == null) {
175
connect();
176
}
177
connection.writeObject(line);
178
}
179
180
/**
181
* Read a text line from this <code>IOPipe</code> channel,
182
* or return <i>null</i> if EOF reached.
183
*
184
* @throws Failure if error occured while reading data
185
*/
186
public String readln() {
187
if (connection == null) {
188
connect();
189
}
190
String line = (String) connection.readObject();
191
return line;
192
}
193
194
/**
195
* Close this <code>IOPipe</code> connection.
196
*/
197
public void close() {
198
shouldStop = true;
199
if (connection != null) {
200
connection.close();
201
}
202
}
203
204
protected class ListenerThread extends Thread {
205
private SocketConnection connection;
206
private RuntimeException error;
207
208
ListenerThread() {
209
super("PipeIO Listener Thread");
210
setDaemon(true);
211
212
connection = new SocketConnection(SocketIOPipe.this, getName());
213
214
if (serverSocket == null) {
215
connection.bind(port, timeout);
216
} else {
217
connection.setServerSocket(serverSocket);
218
}
219
}
220
221
@Override
222
public void run() {
223
synchronized (this) {
224
try {
225
connection.accept(timeout);
226
} catch (Throwable th) {
227
error = th instanceof RuntimeException
228
? (RuntimeException)th
229
: new RuntimeException(th);
230
}
231
notifyAll();
232
}
233
}
234
235
public SocketConnection getConnection() {
236
synchronized (this) {
237
while (!connection.isConnected() && error == null) {
238
try {
239
wait();
240
} catch (InterruptedException e) {
241
}
242
}
243
if (error != null) {
244
throw error;
245
}
246
return connection;
247
}
248
}
249
}
250
251
private ListenerThread listenerThread;
252
253
protected void startListening() {
254
if (listenerThread != null) {
255
throw new TestBug("already listening");
256
}
257
listenerThread = new ListenerThread();
258
listenerThread.start();
259
}
260
261
/**
262
* Establish <code>IOPipe</code> connection by attaching or accepting
263
* connection appropriately.
264
*/
265
protected void connect() {
266
if (connection != null) {
267
throw new TestBug("IOPipe connection is already established");
268
}
269
270
if (shouldStop)
271
return;
272
273
if (listening) {
274
// listenerThread == null means the test is not updated yet
275
// to start IOPipe listening before launching debuggee.
276
if (listenerThread == null) {
277
// start listening and accept connection on the current thread
278
listenerThread = new ListenerThread();
279
listenerThread.run();
280
}
281
connection = listenerThread.getConnection();
282
} else {
283
connection = new SocketConnection(this, getName());
284
// attach from the debuggee's side
285
connection.continueAttach(host, port, timeout);
286
}
287
}
288
289
/**
290
* Set ping timeout in milliseconds (0 means don't use ping at all).
291
*/
292
public void setPingTimeout(long timeout) {
293
if (connection == null) {
294
throw new TestBug("Attempt to set ping timeout for not established connection");
295
}
296
connection.setPingTimeout(timeout);
297
}
298
299
/**
300
* Returns value of current ping timeout in milliseconds (0 means ping is not used).
301
*/
302
public long getPingTimeout() {
303
if (connection == null) {
304
throw new TestBug("Attempt to get ping timeout for not established connection");
305
}
306
return connection.getPingTimeout();
307
}
308
309
/**
310
* Perform finalization of the object by invoking close().
311
*/
312
protected void finalize() throws Throwable {
313
close();
314
super.finalize();
315
}
316
317
/**
318
* Perform finalization of the object at exit by invoking finalize().
319
*/
320
public void finalizeAtExit() throws Throwable {
321
finalize();
322
}
323
324
/**
325
* Field 'pipeCounter' and method 'getNextPipeNumber' are used to construct unique names for SocketIOPipes
326
*/
327
private static int pipeCounter;
328
329
private synchronized int getNextPipeNumber() {
330
return pipeCounter++;
331
}
332
333
/**
334
* Construct name for SocketIOPipe if it wasn't specified
335
*/
336
private String getName() {
337
if (name == null) {
338
name = "SocketIOPipe-" + getNextPipeNumber();
339
}
340
341
return name;
342
}
343
}
344
345