Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java
41161 views
1
/*
2
* Copyright (c) 2001, 2018, 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
24
package nsk.share.jpda;
25
26
import java.io.*;
27
import java.net.*;
28
29
import nsk.share.*;
30
31
/**
32
* This class implements basic connection channel via TCP/IP sockets.
33
*/
34
class BasicSocketConnection {
35
36
protected static int TRACE_LEVEL_PACKETS = 10;
37
38
protected static int TRACE_LEVEL_THREADS = 20;
39
40
protected static int TRACE_LEVEL_ACTIONS = 30;
41
42
protected static int TRACE_LEVEL_SOCKETS = 40;
43
44
protected static int TRACE_LEVEL_IO = 50;
45
46
protected String name = null;
47
48
protected ServerSocket serverSocket = null;
49
50
protected Socket socket = null;
51
52
protected InputStream sin = null;
53
54
protected OutputStream sout = null;
55
56
protected Process connectingProcess = null;
57
58
protected volatile boolean connected = false;
59
60
protected volatile boolean closed = false;
61
62
protected volatile boolean connectionClosed = false;
63
64
protected volatile boolean shouldStop = false;
65
66
protected Log.Logger logger = null;
67
68
/**
69
* Make an empty connection with specified name.
70
*
71
* @param logger
72
* Logger object for printing log messages
73
* @param name
74
* connection name
75
*/
76
public BasicSocketConnection(Log.Logger logger, String name) {
77
this.logger = logger;
78
this.name = name;
79
}
80
81
/**
82
* Try to bind connection to the local port.
83
*
84
* @param port
85
* port number to bind to
86
*
87
* @throws IOException
88
* if error occured while binding
89
*/
90
protected void tryBind(int port) throws IOException {
91
logger.trace(TRACE_LEVEL_IO, "Binding for " + name + " connection to port: " + port);
92
serverSocket = new ServerSocket(port, 1);
93
logger.trace(TRACE_LEVEL_IO, "Bound for " + name + " connection to port: " + port);
94
}
95
96
/**
97
* Bind connection to the local port for specified timeout.
98
*
99
* @param port
100
* port number to bind to
101
* @param timeout
102
* binding timeout in milliseconds
103
*
104
* @throws Failure
105
* if error ocured while binding
106
*/
107
protected void bind(int port, long timeout) {
108
BindException bindException = null;
109
long timeToFinish = System.currentTimeMillis() + timeout;
110
for (long i = 0; !shouldStop && (timeout == 0 || System.currentTimeMillis() < timeToFinish); i++) {
111
try {
112
tryBind(port);
113
return;
114
} catch (BindException e) {
115
bindException = e;
116
logger.display("Attempt #" + i + " to bind to port " + port + " failed:\n\t" + e);
117
try {
118
Thread.sleep(DebugeeBinder.CONNECT_TRY_DELAY);
119
} catch (InterruptedException ie) {
120
ie.printStackTrace(logger.getOutStream());
121
throw new Failure("Thread interrupted while binding for " + name + " connection to port " + port + ":\n\t" + ie);
122
}
123
} catch (IOException e) {
124
e.printStackTrace(logger.getOutStream());
125
throw new Failure("Caught IOException while binding for " + name + " connection to port " + port + ":\n\t" + e);
126
}
127
}
128
throw new Failure("Unable to bind for " + name + " connection to port " + port + " for " + timeout + "ms timeout:\n\t" + bindException);
129
}
130
131
/**
132
* Accept connection at the bound port for specified timeout.
133
*
134
* @param timeout
135
* accepting timeout in milliseconds
136
*
137
* @throws Failure
138
* if error occured while accepting connection
139
*/
140
public void accept(long timeout) {
141
int port = serverSocket.getLocalPort();
142
logger.trace(TRACE_LEVEL_IO, "Listening for " + name + " connection at port: " + port);
143
socket = null;
144
try {
145
if (timeout > Integer.MAX_VALUE) {
146
throw new TestBug("Too large timeout long value: " + timeout + " (can't cast it to int)");
147
}
148
149
serverSocket.setSoTimeout((int)timeout);
150
151
long waitStartTime = System.currentTimeMillis();
152
153
/*
154
* We found that sometimes (very rarely) on Solaris ServerSocket.accept() throws InterruptedIOException
155
* even if connection timeout (specified through ServerSocket.setSoTimeout) didn't expire.
156
* Following code tries to catch such case and call ServerSocket.accept() while timeout didn't expire.
157
*/
158
do {
159
try {
160
socket = serverSocket.accept();
161
logger.trace(TRACE_LEVEL_IO, "Accepted " + name + " connection at port: " + port);
162
} catch (InterruptedIOException e) {
163
long interruptTime = System.currentTimeMillis();
164
long waitTime = interruptTime - waitStartTime;
165
166
logger.display("Caught InterruptedIOException. Wait start time: " + waitStartTime + ", exception was thrown at: "
167
+ interruptTime + ", wait time: " + (interruptTime - waitStartTime) + ", actual timeout: " + timeout);
168
169
// if waitTime was too small call ServerSocket.accept() one more time
170
if (!shouldStop && (waitTime < (timeout / 2))) {
171
logger.display("InterruptedIOException was thrown too early, trying to call ServerSocket.accept() one more time");
172
continue;
173
} else {
174
if (!shouldStop) {
175
logger.complain("Caught InterruptedIOException while listening for " + name + " connection at port " + port + ":\n\t" + e);
176
throw new Failure("Connection for " + name +
177
" at port " + port +
178
" wasn't accepted in " + timeout + "ms");
179
} else {
180
logger.display("Listening was interrupted (caught InterruptedIOException while listening for " + name + " connection at port " + port + ":\n\t" + e + ")");
181
break;
182
}
183
}
184
}
185
} while (socket == null);
186
187
} catch (IOException e) {
188
if (!shouldStop) {
189
e.printStackTrace(logger.getOutStream());
190
throw new Failure("Caught IOException while listening for " + name + " connection at port " + port + ":\n\t" + e);
191
} else {
192
logger.display("Listening was interrupted (caught InterruptedIOException while listening for " + name + " connection at port " + port + ":\n\t" + e + ")");
193
}
194
} finally {
195
closeServerConnection();
196
}
197
198
if (!shouldStop) {
199
if (socket == null) {
200
throw new Failure("No " + name + " connection accepted at port " + port + " for " + timeout + "ms timeout");
201
}
202
203
onConnected();
204
}
205
}
206
207
/**
208
* Attach connection to the remote host and port.
209
*
210
* @param host
211
* name of remote host to attach to
212
* @param port
213
* port number to attach to
214
*
215
* @throws Failure
216
* if error occured while attaching
217
*/
218
public void attach(String host, int port) {
219
try {
220
logger.trace(TRACE_LEVEL_IO, "Attaching for " + name + " connection to host: " + host + ":" + port);
221
socket = new Socket(host, port);
222
socket.setTcpNoDelay(true);
223
logger.trace(TRACE_LEVEL_IO, "Attached for " + name + " connection to host: " + host + ":" + port);
224
} catch (IOException e) {
225
e.printStackTrace(logger.getOutStream());
226
throw new Failure("Caught IOException while attaching for " + name + " connection to " + host + ":" + port + ":\n\t" + e);
227
}
228
if (!shouldStop) {
229
onConnected();
230
}
231
}
232
233
/**
234
* Continuously attach to the remote host for the specified timeout.
235
*
236
* @param host
237
* name of remote host to attach to
238
* @param port
239
* port number to attach to
240
* @param timeout
241
* attaching timeout in milliseconds
242
*
243
* @throws Failure
244
* if error occured while attaching
245
*/
246
public void continueAttach(String host, int port, long timeout) {
247
socket = null;
248
long timeToFinish = System.currentTimeMillis() + timeout;
249
ConnectException lastException = null;
250
logger.trace(TRACE_LEVEL_IO, "Attaching for " + name + " connection to host: " + host + ":" + port);
251
try {
252
for (long i = 0; !shouldStop && (timeout == 0 || System.currentTimeMillis() < timeToFinish); i++) {
253
try {
254
socket = new Socket(host, port);
255
logger.trace(TRACE_LEVEL_IO, "Attached for " + name + " connection to host: " + host + ":" + port);
256
break;
257
} catch (ConnectException e) {
258
logger.display("Attempt #" + i + " to attach for " + name + " connection failed:\n\t" + e);
259
lastException = e;
260
// check if listening process still alive
261
if (!checkConnectingProcess()) {
262
shouldStop = true;
263
throw new Failure("Break attaching to " + name + " connection: " + "listening process exited");
264
}
265
// sleep between attempts
266
try {
267
Thread.sleep(DebugeeBinder.CONNECT_TRY_DELAY);
268
} catch (InterruptedException ie) {
269
throw new Failure("Thread interrupted while attaching for " + name + " connection to " + host + ":" + port + ":\n\t" + ie);
270
}
271
}
272
}
273
274
} catch (IOException e) {
275
e.printStackTrace(logger.getOutStream());
276
throw new Failure("Caught IOException while attaching for " + name + " connection to " + host + ":" + port + ":\n\t" + e);
277
}
278
279
if (!shouldStop) {
280
if (socket == null) {
281
throw new Failure("Unable to attach for " + name + " connection to " + host + ":" + port + " for " + timeout + "ms timeout:\n\t"
282
+ lastException);
283
}
284
285
onConnected();
286
}
287
}
288
289
/**
290
* Set already bound serverSocket for further connection.
291
*/
292
public void setServerSocket(ServerSocket serverSocket) {
293
this.serverSocket = serverSocket;
294
}
295
296
/**
297
* Set already connected socket for connection.
298
*/
299
public void setSocket(Socket socket) {
300
this.socket = socket;
301
if (!shouldStop) {
302
onConnected();
303
}
304
}
305
306
/**
307
* Get socket of already established connection.
308
*/
309
public Socket getSocket() {
310
return socket;
311
}
312
313
/**
314
* Return true if another connecting process is still alive.
315
*/
316
public boolean checkConnectingProcess() {
317
if (connectingProcess == null) {
318
// no process to check
319
return true;
320
}
321
try {
322
int exitCode = connectingProcess.exitValue();
323
} catch (IllegalThreadStateException e) {
324
// process is still alive
325
return true;
326
}
327
// process exited
328
return false;
329
}
330
331
/**
332
* Set another connecting process to control if it is still alive.
333
*/
334
public void setConnectingProcess(Process process) {
335
connectingProcess = process;
336
}
337
338
/**
339
* Check if connection is established.
340
*/
341
public boolean isConnected() {
342
return connected;
343
}
344
345
/**
346
* Close socket and associated streams.
347
*/
348
public void close() {
349
if (!closed) {
350
shouldStop = true;
351
closeConnection();
352
closed = true;
353
}
354
}
355
356
/**
357
* Send the specified byte throw the connection.
358
*/
359
public void writeByte(byte b) throws IOException {
360
logger.trace(TRACE_LEVEL_IO, "Writing byte: " + b);
361
sout.write(b);
362
sout.flush();
363
logger.trace(TRACE_LEVEL_IO, "Wrote byte: " + b);
364
}
365
366
/**
367
* Read a byte and return it or -1.
368
*/
369
public int readByte() throws IOException {
370
logger.trace(TRACE_LEVEL_IO, "Reading byte");
371
int b = sin.read();
372
logger.trace(TRACE_LEVEL_IO, "Received byte: " + b);
373
return b;
374
}
375
376
/**
377
* Perform some actions after connection established.
378
*/
379
protected void onConnected() {
380
if (!shouldStop) {
381
setSocketOptions();
382
makeSocketStreams();
383
connected = true;
384
}
385
}
386
387
/**
388
* Set socket options after connection established.
389
*/
390
protected void setSocketOptions() {
391
}
392
393
/**
394
* Close server socket.
395
*/
396
protected void closeServerConnection() {
397
if (serverSocket != null) {
398
try {
399
serverSocket.close();
400
logger.trace(TRACE_LEVEL_IO, "ServerSocket closed: " + serverSocket);
401
} catch (IOException e) {
402
logger.display("# WARNING: " + "Caught IOException while closing ServerSocket of " + name + " connection:\n\t" + e);
403
}
404
}
405
}
406
407
/**
408
* Close socket of connection to remote host.
409
*/
410
protected void closeHostConnection() {
411
if (socket != null) {
412
try {
413
socket.close();
414
logger.trace(TRACE_LEVEL_IO, "Socket closed: " + socket);
415
} catch (IOException e) {
416
logger.display("# WARNING: " + "Caught IOException while closing socket of " + name + " connection:\n\t" + e);
417
}
418
}
419
}
420
421
/**
422
* Close socket streams.
423
*/
424
protected void closeSocketStreams() {
425
if (sout != null) {
426
try {
427
logger.trace(TRACE_LEVEL_IO, "Closing socket output stream: " + sout);
428
sout.close();
429
logger.trace(TRACE_LEVEL_IO, "Output stream closed: " + sout);
430
} catch (IOException e) {
431
logger.display("# WARNING: " + "Caught IOException while closing OutputStream of " + name + " connection:\n\t" + e);
432
}
433
}
434
if (sin != null) {
435
try {
436
logger.trace(TRACE_LEVEL_IO, "Closing socket input stream: " + sin);
437
sin.close();
438
logger.trace(TRACE_LEVEL_IO, "Input stream closed: " + sin);
439
} catch (IOException e) {
440
logger.display("# WARNING: " + "Caught IOException while closing InputStream of" + name + " connection:\n\t" + e);
441
}
442
}
443
}
444
445
/**
446
* Close sockets and associated streams.
447
*/
448
protected void closeConnection() {
449
if (connectionClosed)
450
return;
451
452
logger.trace(TRACE_LEVEL_IO, "Closing " + name + " connection");
453
closeSocketStreams();
454
closeHostConnection();
455
closeServerConnection();
456
connectionClosed = true;
457
}
458
459
/**
460
* Make up socket streams after connection established.
461
*/
462
protected void makeSocketStreams() {
463
try {
464
logger.trace(TRACE_LEVEL_IO, "Getting input/output socket streams for " + name + " connection");
465
sout = socket.getOutputStream();
466
logger.trace(TRACE_LEVEL_IO, "Got socket output stream: " + sout);
467
sin = socket.getInputStream();
468
logger.trace(TRACE_LEVEL_IO, "Got socket input stream: " + sin);
469
} catch (IOException e) {
470
e.printStackTrace(logger.getOutStream());
471
throw new Failure("Caught exception while making streams for " + name + " connection:\n\t" + e);
472
}
473
}
474
475
} // BasicSocketConnection
476
477
/**
478
* This class implements connection channel via TCP/IP sockets. After connection
479
* established special inner threads are started, which periodically test the
480
* connection by pinging each other. If ping timeout occurs connection is closed
481
* and any thread waiting for read from this connection gets exception.
482
*
483
* @see #setPingTimeout(long)
484
*/
485
public class SocketConnection extends BasicSocketConnection {
486
487
private static final long PING_INTERVAL = 1 * 1000; // milliseconds
488
489
private static byte DATA_BYTE = (byte) 0x03;
490
491
private static byte DISCONNECT_BYTE = (byte) 0x04;
492
493
private final Object inLock = new Object();
494
private ObjectInputStream in = null;
495
496
private final Object outLock = new Object();
497
private ObjectOutputStream out = null;
498
499
private volatile long pingTimeout = 0; // don't use ping
500
501
/**
502
* Make an empty connection with specified name.
503
*
504
* @param log
505
* Log object for printing log messages
506
* @param name
507
* connection name
508
*/
509
public SocketConnection(Log log, String name) {
510
this(new Log.Logger(log, name + " connection> "), name);
511
}
512
513
/**
514
* Make an empty connection with specified name.
515
*
516
* @param logger
517
* Logger object for printing log messages
518
* @param name
519
* connection name
520
*/
521
public SocketConnection(Log.Logger logger, String name) {
522
super(logger, name);
523
}
524
525
/**
526
* Set ping timeout in milliseconds (0 means don't use ping at all).
527
*/
528
public void setPingTimeout(long timeout) {
529
logger.display("# WARNING: Setting ping timeout for " + name + " connection ingnored: " + timeout + " ms");
530
pingTimeout = timeout;
531
}
532
533
/**
534
* Returns value of current ping timeout in milliseconds (0 means ping is
535
* not used).
536
*/
537
public long getPingTimeout() {
538
return pingTimeout;
539
}
540
541
/**
542
* Receive an object from remote host.
543
*/
544
public Object readObject() {
545
if (!isConnected()) {
546
throw new Failure("Unable to read object from not established " + name + " connection");
547
}
548
549
try {
550
return doReadObject();
551
} catch (EOFException e) {
552
return null;
553
} catch (Exception e) {
554
e.printStackTrace(logger.getOutStream());
555
throw new Failure("Caught Exception while reading an object from " + name + " connection:\n\t" + e);
556
}
557
}
558
559
/**
560
* Send an object to remote host.
561
*/
562
public void writeObject(Object object) {
563
if (!isConnected()) {
564
throw new Failure("Unable to send object throw not established " + name + " connection:\n\t" + object);
565
}
566
567
try {
568
doWriteObject(object);
569
} catch (IOException e) {
570
e.printStackTrace(logger.getOutStream());
571
throw new Failure("Caught IOException while writing an object to " + name + " connection:\n\t" + e);
572
}
573
}
574
575
/**
576
* Close socket and associated streams and finish all internal threads.
577
*/
578
public void close() {
579
if (!closed) {
580
// disconnect();
581
shouldStop = true;
582
super.close();
583
closed = true;
584
}
585
}
586
587
/**
588
* Perform some actions after connection has established.
589
*/
590
protected void onConnected() {
591
super.onConnected();
592
}
593
594
/**
595
* Do write an object to the connection channel.
596
*/
597
private void doWriteObject(Object object) throws IOException {
598
logger.trace(TRACE_LEVEL_IO, "writing object: " + object);
599
synchronized(outLock) {
600
out.writeObject(object);
601
out.flush();
602
}
603
logger.trace(TRACE_LEVEL_PACKETS, "* sent: " + object);
604
}
605
606
/**
607
* Do read an object from the connection channel.
608
*/
609
private Object doReadObject() throws IOException, ClassNotFoundException {
610
logger.trace(TRACE_LEVEL_IO, "Reading object");
611
Object object = null;
612
synchronized(inLock) {
613
object = in.readObject();
614
}
615
logger.trace(TRACE_LEVEL_PACKETS, "* recv: " + object);
616
return object;
617
}
618
619
/**
620
* Close socket streams.
621
*/
622
protected void closeSocketStreams() {
623
synchronized(outLock) {
624
if (out != null) {
625
try {
626
logger.trace(TRACE_LEVEL_IO, "Closing socket output stream: " + out);
627
out.close();
628
logger.trace(TRACE_LEVEL_IO, "Output stream closed: " + out);
629
} catch (IOException e) {
630
logger.display("# WARNING: " + "Caught IOException while closing ObjectOutputStream of " + name + " connection:\n\t" + e);
631
}
632
}
633
}
634
synchronized(inLock) {
635
if (in != null) {
636
try {
637
logger.trace(TRACE_LEVEL_IO, "Closing socket input stream: " + in);
638
in.close();
639
logger.trace(TRACE_LEVEL_IO, "Input stream closed: " + in);
640
} catch (IOException e) {
641
logger.display("# WARNING: " + "Caught IOException while closing ObjectInputStream of" + name + " connection:\n\t" + e);
642
}
643
}
644
}
645
super.closeSocketStreams();
646
}
647
648
/**
649
* Close sockets and associated streams.
650
*/
651
protected void closeConnection() {
652
if (connectionClosed)
653
return;
654
connected = false;
655
shouldStop = true;
656
super.closeConnection();
657
}
658
659
/**
660
* Make up object streams for socket.
661
*/
662
protected void makeSocketStreams() {
663
try {
664
logger.trace(TRACE_LEVEL_IO, "Making input/output object streams for " + name + " connection");
665
synchronized(outLock) {
666
out = new ObjectOutputStream(socket.getOutputStream());
667
out.flush();
668
}
669
logger.trace(TRACE_LEVEL_IO, "Output stream created: " + out);
670
synchronized(inLock) {
671
in = new ObjectInputStream(socket.getInputStream());
672
}
673
logger.trace(TRACE_LEVEL_IO, "Input stream created: " + in);
674
} catch (IOException e) {
675
e.printStackTrace(logger.getOutStream());
676
throw new Failure("Caught exception while making streams for " + name + " connection:\n\t" + e);
677
}
678
}
679
680
} // SocketConnection
681
682