Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeBinder.java
41161 views
1
/*
2
* Copyright (c) 2001, 2019, 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 nsk.share.*;
27
28
import java.io.*;
29
import java.net.*;
30
import java.util.*;
31
32
/**
33
* This class provides debugger with ability to launch
34
* debuggee VM and to make connection to it using JDI connector or
35
* JDWP transport.
36
* <p>
37
* The present version of <code>Binder</code> allows
38
* to launch debuggee VM either on local machine (<i>local</i> launch mode),
39
* or on remote host using <code>BindServer</code> utility
40
* (<i>remote</i> launch mode). Also there is an ability to launch
41
* debuggee VM manually as a separate process on local or remote machine
42
* (<i>manual</i> launch mode), which is usefull for debugging.
43
* All these launching modes are specified by command line option
44
* <code>-debugee.launch</code> recognized by <code>DebugeeArgumentHandler</code>.
45
* <p>
46
* <code>Binder</code> also makes it possible to establish TCP/IP
47
* connection between debugger and debuggee throw <code>IOPipe</code>
48
* object. This connection allows debugger to communicate with debuggee
49
* by exchanging with synchronization messages and data.
50
* <p>
51
* To launch debuggee VM and bind to it use <code>bindToDebugee()</code>
52
* method. This method construct mirror of debugee VM, represented by
53
* object of <code>DebugeeProcess</code> class or derived. This mirror object
54
* allows to control debuggee VM.
55
* <p>
56
* See also <code>nsk.share.jdi.Binder</code> and <code>nsk.share.jdwp.Binder</code>
57
* classes which provide launching and binding to debuggee VM using specific
58
* JDI and JDWP features.
59
*
60
* @see DebugeeArgumentHandler
61
* @see DebugeeProcess
62
* @see IOPipe
63
* @see BindServer
64
*
65
* @see nsk.share.jdi.Binder
66
* @see nsk.share.jdwp.Binder
67
*/
68
public class DebugeeBinder extends Log.Logger implements Finalizable {
69
70
private static final boolean IS_WINDOWS = System.getProperty("os.name")
71
.toLowerCase()
72
.startsWith("win");
73
74
public static int TRY_DELAY = 1000; // milliseconds
75
76
public static int CONNECT_TIMEOUT = 1 * 60 * 1000; // milliseconds
77
public static int CONNECT_TRY_DELAY = 2 * 1000; // milliseconds
78
public static int CONNECT_TRIES = CONNECT_TIMEOUT / CONNECT_TRY_DELAY;
79
80
public static int THREAD_TIMEOUT = 2 * CONNECT_TRY_DELAY; // milliseconds
81
public static int PING_TIMEOUT = 30 * 1000; // milliseconds
82
83
public static int SOCKET_TIMEOUT = 2 * 1000; // milliseconds
84
public static int SOCKET_LINGER = 1; // milliseconds
85
86
private static int TRACE_LEVEL_PACKETS = 10;
87
private static int TRACE_LEVEL_THREADS = 20;
88
private static int TRACE_LEVEL_ACTIONS = 30;
89
private static int TRACE_LEVEL_SOCKETS = 40;
90
private static int TRACE_LEVEL_IO = 50;
91
92
/**
93
* Default message prefix for <code>Binder</code> object.
94
*/
95
public static final String LOG_PREFIX = "binder> ";
96
97
private DebugeeArgumentHandler argumentHandler = null;
98
99
/**
100
* Get version string.
101
*/
102
public static String getVersion () {
103
return "@(#)Binder.java %I% %E%";
104
}
105
106
// -------------------------------------------------- //
107
108
private BindServerListener bindServerListener = null;
109
private ServerSocket pipeServerSocket = null;
110
111
// -------------------------------------------------- //
112
113
/**
114
* Incarnate new Binder obeying the given
115
* <code>argumentHandler</code>; and assign the given
116
* <code>log</code>.
117
*/
118
public DebugeeBinder (DebugeeArgumentHandler argumentHandler, Log log) {
119
super(log, LOG_PREFIX);
120
this.argumentHandler = argumentHandler;
121
Finalizer finalizer = new Finalizer(this);
122
finalizer.activate();
123
}
124
125
/**
126
* Get argument handler of this binder object.
127
*/
128
DebugeeArgumentHandler getArgumentHandler() {
129
return argumentHandler;
130
}
131
132
// -------------------------------------------------- //
133
134
/**
135
* Wait for given thread finished for THREAD_TIMEOUT timeout and
136
* interrupt this thread if not finished.
137
*
138
* @param thr thread to wait for
139
* @param logger to write log messages to
140
*/
141
public static void waitForThread(Thread thr, Log.Logger logger) {
142
waitForThread(thr, THREAD_TIMEOUT, logger);
143
}
144
145
/**
146
* Wait for given thread finished for specified timeout and
147
* interrupt this thread if not finished.
148
*
149
* @param thr thread to wait for
150
* @param millisecs timeout in milliseconds
151
* @param logger to write log messages to
152
*/
153
public static void waitForThread(Thread thr, long millisecs, Log.Logger logger) {
154
if (thr != null) {
155
if (thr.isAlive()) {
156
try {
157
logger.trace(TRACE_LEVEL_THREADS, "Waiting for thread: " + thr.getName());
158
thr.join(millisecs);
159
} catch (InterruptedException e) {
160
e.printStackTrace(logger.getOutStream());
161
throw new Failure ("Thread interrupted while waiting for another thread:\n\t"
162
+ e);
163
} finally {
164
if (thr.isAlive()) {
165
logger.trace(TRACE_LEVEL_THREADS, "Interrupting not finished thread: " + thr);
166
thr.interrupt();
167
}
168
}
169
}
170
}
171
}
172
173
174
/**
175
* Make preperation for IOPipe connection before starting debugee VM process.
176
* May change options in the passed <code>argumentHandler</code>.
177
*/
178
public void prepareForPipeConnection(DebugeeArgumentHandler argumentHandler) {
179
if (argumentHandler.isTransportAddressDynamic()) {
180
try {
181
pipeServerSocket = new ServerSocket();
182
pipeServerSocket.setReuseAddress(false);
183
pipeServerSocket.bind(null);
184
185
} catch (IOException e) {
186
e.printStackTrace(getOutStream());
187
throw new Failure("Caught IOException while binding for IOPipe connection: \n\t"
188
+ e);
189
}
190
191
int port = pipeServerSocket.getLocalPort();
192
argumentHandler.setPipePortNumber(port);
193
}
194
}
195
196
/**
197
* Return already bound ServerSocket for IOPipe connection or null.
198
*/
199
protected ServerSocket getPipeServerSocket() {
200
return pipeServerSocket;
201
}
202
203
/**
204
* Close ServerSocket used for IOPipeConnection if any.
205
*/
206
private void closePipeServerSocket() {
207
if (pipeServerSocket != null) {
208
try {
209
pipeServerSocket.close();
210
} catch (IOException e) {
211
println("# WARNING: Caught IOException while closing ServerSocket used for IOPipe connection: \n\t"
212
+ e);
213
}
214
}
215
}
216
217
// -------------------------------------------------- //
218
219
/**
220
* Make environment for launching JVM process.
221
*/
222
public String[] makeProcessEnvironment() {
223
/*
224
String env = new String[0];
225
return env;
226
*/
227
return null;
228
}
229
230
/**
231
* Launch process by the specified command line.
232
*
233
* @throws IOException if I/O error occured while launching process
234
*/
235
public Process launchProcess(String cmdLine) throws IOException {
236
String env[] = makeProcessEnvironment();
237
return Runtime.getRuntime().exec(cmdLine, env);
238
}
239
240
/**
241
* Launch process by the arguments array.
242
*
243
* @throws IOException if I/O error occured while launching process
244
*/
245
public Process launchProcess(String[] args) throws IOException {
246
String env[] = makeProcessEnvironment();
247
return Runtime.getRuntime().exec(args, env);
248
}
249
250
/**
251
* Make string representation of debuggee VM transport address according
252
* to current command line options.
253
*/
254
public String makeTransportAddress() {
255
String address = null;
256
if (argumentHandler.isSocketTransport()) {
257
if (argumentHandler.isListeningConnector()) {
258
address = argumentHandler.getTestHost()
259
+ ":" + argumentHandler.getTransportPort();
260
} else {
261
address = argumentHandler.getTransportPort();
262
}
263
} else if (argumentHandler.isShmemTransport() ) {
264
address = argumentHandler.getTransportSharedName();
265
} else {
266
throw new TestBug("Undefined transport type: "
267
+ argumentHandler.getTransportType());
268
}
269
return address;
270
}
271
272
/**
273
* Make command line to launch debugee VM as a string using given quote symbol,
274
* using specified <code>transportAddress</code> for JDWP connection.
275
*/
276
public String makeCommandLineString(String classToExecute, String transportAddress, String quote) {
277
String[] args = makeCommandLineArgs(classToExecute, transportAddress);
278
return ArgumentParser.joinArguments(args, quote);
279
}
280
281
/**
282
* Make command line to launch debugee VM as a string using given quote symbol.
283
*/
284
public String makeCommandLineString(String classToExecute, String quote) {
285
return makeCommandLineString(classToExecute, makeTransportAddress(), quote);
286
}
287
288
/**
289
* Make command line to launch debugee VM as a string using default quote symbol,
290
* using specified <code>transportAddress</code> for JDWP connection.
291
*/
292
/*
293
public String makeCommandLineString(String classToExecute, String transportAddress) {
294
return makeCommandLineString(classToExecute, transportAddress, "\"");
295
}
296
*/
297
298
/**
299
* Make command line to launch debugee VM as a string using default quote symbol.
300
*/
301
/*
302
public String makeCommandLineString(String classToExecute) {
303
return makeCommandLineString(classToExecute, makeTransportAddress());
304
}
305
*/
306
307
/**
308
* Make command line to launch debugee VM as an array of arguments,
309
* using specified <code>transportAddress</code> for JDWP connection.
310
*/
311
public String[] makeCommandLineArgs(String classToExecute, String transportAddress) {
312
Vector<String> args = new Vector<String>();
313
314
args.add(argumentHandler.getLaunchExecPath());
315
316
String javaOpts = argumentHandler.getLaunchOptions();
317
if (javaOpts != null && javaOpts.length() > 0) {
318
StringTokenizer st = new StringTokenizer(javaOpts);
319
320
while (st.hasMoreTokens()) {
321
args.add(st.nextToken());
322
}
323
}
324
325
/*
326
String classPath = System.getProperty("java.class.path");
327
args.add("-classpath")
328
args.add(classPath);
329
*/
330
331
args.add("-Xdebug");
332
333
String server;
334
if (argumentHandler.isAttachingConnector()) {
335
server = "y";
336
} else {
337
server = "n";
338
}
339
340
String jdwpArgs = "-Xrunjdwp:"
341
+ "server=" + server
342
+ ",transport=" + argumentHandler.getTransportName()
343
+ ",address=" + transportAddress;
344
345
if (! argumentHandler.isDefaultJVMDIStrictMode()) {
346
if (argumentHandler.isJVMDIStrictMode())
347
jdwpArgs += ",strict=y";
348
else
349
jdwpArgs += ",strict=n";
350
}
351
352
args.add(jdwpArgs);
353
354
if (classToExecute != null) {
355
StringTokenizer st = new StringTokenizer(classToExecute);
356
357
while (st.hasMoreTokens()) {
358
args.add(st.nextToken());
359
}
360
}
361
362
String[] rawArgs = argumentHandler.getRawArguments();
363
for (int i = 0; i < rawArgs.length; i++) {
364
String rawArg = rawArgs[i];
365
// " has to be escaped on windows
366
if (IS_WINDOWS) {
367
rawArg = rawArg.replace("\"", "\\\"");
368
}
369
args.add(rawArg);
370
}
371
372
String[] argsArray = new String[args.size()];
373
for (int i = 0; i < args.size(); i++) {
374
argsArray[i] = (String) args.elementAt(i);
375
}
376
377
return argsArray;
378
}
379
380
/**
381
* Make command line to launch debugee VM as an array of arguments.
382
*/
383
public String[] makeCommandLineArgs(String classToExecute) {
384
return makeCommandLineArgs(classToExecute, makeTransportAddress());
385
}
386
387
/**
388
* Make connection to remote BindServer and start BindServerListener thread.
389
*
390
* @throws IOException if I/O error occured while connecting
391
*/
392
public void connectToBindServer(String taskID) {
393
if (bindServerListener != null) {
394
throw new Failure("Connection to BindServer already exists");
395
}
396
try {
397
bindServerListener = new BindServerListener(this);
398
bindServerListener.setDaemon(true);
399
bindServerListener.connect(taskID);
400
bindServerListener.start();
401
} catch (IOException e) {
402
e.printStackTrace(getOutStream());
403
throw new Failure("Caught exception while connecting to BindServer:\n\t" + e);
404
}
405
}
406
407
/**
408
* Split string into list of substrings using specified separator.
409
*/
410
private static String[] splitString(String givenString, String separator) {
411
Vector<String> tmpList = new Vector<String>();
412
StringTokenizer tokenizer = new StringTokenizer(givenString, separator);
413
while(tokenizer.hasMoreTokens()) {
414
tmpList.add(tokenizer.nextToken());
415
}
416
String[] list = new String[tmpList.size()];
417
for (int i = 0; i < tmpList.size(); i++) {
418
list[i] = tmpList.elementAt(i);
419
}
420
return list;
421
}
422
423
/**
424
* Send command to remote <code>BindServer</code> and receive reply.
425
*
426
* @throws IOException if I/O error occured while launching process
427
*/
428
public synchronized Object sendRemoteCommand(Object command) {
429
try {
430
bindServerListener.sendCommand(command);
431
Object reply = bindServerListener.getReply();
432
return reply;
433
} catch (IOException e) {
434
e.printStackTrace(log.getOutStream());
435
throw new Failure("Unexpected exception while sending command to BindServer:\n\t"
436
+ e);
437
}
438
}
439
440
/**
441
* Launch remote process using request to <code>BindServer</code>.
442
*
443
* @throws IOException if I/O error occured
444
*/
445
public void launchRemoteProcess(String[] args) throws IOException {
446
String pathSeparator = System.getProperty("path.separator");
447
BindServer.LaunchDebugee command =
448
new BindServer.LaunchDebugee(args,
449
System.getProperty("file.separator"),
450
System.getProperty("user.dir"),
451
splitString(System.getProperty("java.library.path"), pathSeparator),
452
splitString(System.getProperty("java.class.path"), pathSeparator),
453
splitString(System.getProperty("java.library.path"), pathSeparator));
454
455
Object reply = sendRemoteCommand(command);
456
if (reply instanceof BindServer.OK) {
457
// do nothing
458
} else if (reply instanceof BindServer.RequestFailed) {
459
BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
460
throw new Failure("BindServer error: " + castedReply.reason);
461
} else {
462
throw new Failure("Wrong reply from BindServer: " + reply);
463
}
464
}
465
466
/**
467
* Return exit status of the remotely launched process
468
* using request to <code>BindServer</code>.
469
*/
470
public int getRemoteProcessStatus () {
471
Object reply = sendRemoteCommand(new BindServer.DebugeeExitCode());
472
if (reply instanceof BindServer.OK) {
473
BindServer.OK castedReply = (BindServer.OK)reply;
474
return (int)castedReply.info;
475
} else if (reply instanceof BindServer.CaughtException) {
476
BindServer.CaughtException castedReply = (BindServer.CaughtException)reply;
477
throw new IllegalThreadStateException(castedReply.reason);
478
} else if (reply instanceof BindServer.RequestFailed) {
479
BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
480
throw new Failure("BindServer error: " + castedReply.reason);
481
} else {
482
throw new Failure("Wrong reply from BindServer: " + reply);
483
}
484
}
485
486
/**
487
* Check whether the remotely launched process has been terminated
488
* using request to <code>BindServer</code>.
489
*/
490
public boolean isRemoteProcessTerminated () {
491
try {
492
int value = getRemoteProcessStatus();
493
return true;
494
} catch (IllegalThreadStateException e) {
495
return false;
496
}
497
}
498
499
// ---------------------------------------------- //
500
501
/**
502
* Kill the remotely launched process
503
* using request to <code>BindServer</code>.
504
*/
505
public void killRemoteProcess () {
506
Object reply = sendRemoteCommand(new BindServer.KillDebugee());
507
if (reply instanceof BindServer.OK) {
508
return;
509
} else if (reply instanceof BindServer.RequestFailed) {
510
BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
511
throw new Failure("BindServer error: " + castedReply.reason);
512
} else {
513
throw new Failure("Wrong reply from BindServer: " + reply);
514
}
515
}
516
517
/**
518
* Wait until the remotely launched process exits or crashes
519
* using request to <code>BindServer</code>.
520
*/
521
public int waitForRemoteProcess () {
522
523
Object reply = sendRemoteCommand(new BindServer.WaitForDebugee(0));
524
if (reply instanceof BindServer.OK) {
525
BindServer.OK castedReply = (BindServer.OK)reply;
526
return (int)castedReply.info;
527
} else if (reply instanceof BindServer.RequestFailed) {
528
BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
529
throw new Failure("BindServer error: " + castedReply.reason);
530
} else {
531
throw new Failure("Wrong reply from BindServer: " + reply);
532
}
533
}
534
535
/**
536
* Close binder by closing all started threads.
537
*/
538
public void close() {
539
if (bindServerListener != null) {
540
bindServerListener.close();
541
}
542
closePipeServerSocket();
543
}
544
545
/**
546
* Finalize binder by invoking <code>close()</code>.
547
*
548
* @throws Throwable if any throwable exception is thrown during finalization
549
*/
550
protected void finalize() throws Throwable {
551
close();
552
super.finalize();
553
}
554
555
/**
556
* Finalize binder at exit by invoking <code>finalize()</code>.
557
*
558
* @throws Throwable if any throwable exception is thrown during finalization
559
*/
560
public void finalizeAtExit() throws Throwable {
561
finalize();
562
}
563
564
/**
565
* Separate thread for listening connection from <code>BindServer</code>.
566
*/
567
private class BindServerListener extends Thread {
568
private SocketConnection connection = null;
569
private Log.Logger logger = null;
570
571
/** List of received responses from <code>BindServer</code>. */
572
private LinkedList<BindServer.Response> replies = new LinkedList<BindServer.Response>();
573
574
/**
575
* Make thread.
576
*/
577
public BindServerListener(Log.Logger logger) {
578
this.logger = logger;
579
}
580
581
/**
582
* Establish connection to <code>BindServer</code>.
583
*/
584
public void connect(String taskID) throws IOException {
585
String host = argumentHandler.getDebugeeHost();
586
int port = argumentHandler.getBindPortNumber();
587
display("Connecting to BindServer: " + host + ":" + port);
588
connection = new SocketConnection(logger, "BindServer");
589
// connection.setPingTimeout(DebugeeBinder.PING_TIMEOUT);
590
connection.attach(host, port);
591
handshake(taskID);
592
}
593
594
/**
595
* Receive OK(version) from BindServer and check received version number.
596
*/
597
private void handshake(String taskID) {
598
// receive OK(version)
599
trace(TRACE_LEVEL_ACTIONS, "Waiting for initial OK(version) from BindServer");
600
Object reply = connection.readObject();
601
trace(TRACE_LEVEL_ACTIONS, "Got initial OK(version) from BindServer: " + reply);
602
if (reply instanceof BindServer.RequestFailed) {
603
BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
604
trace(TRACE_LEVEL_ACTIONS, "Reply is RequestFailed: throw Failure");
605
throw new Failure("BindServer error: " + castedReply.reason);
606
} else if (reply instanceof BindServer.OK) {
607
BindServer.OK castedReply = (BindServer.OK)reply;
608
trace(TRACE_LEVEL_ACTIONS, "Reply is OK: check BindServer version");
609
if (castedReply.info != BindServer.VERSION) {
610
throw new Failure("Wrong version of BindServer: " + castedReply.info
611
+ " (expected: " + BindServer.VERSION + ")");
612
}
613
display("Connected to BindServer: version " + castedReply.info);
614
} else {
615
trace(TRACE_LEVEL_ACTIONS, "Reply is unknown: throw Failure");
616
throw new Failure("Wrong reply from BindServer: " + reply);
617
}
618
619
// send TaskID(id)
620
try {
621
trace(TRACE_LEVEL_ACTIONS, "Sending TaskID(id) to BindServer");
622
sendCommand(new BindServer.TaskID(taskID));
623
trace(TRACE_LEVEL_ACTIONS, "Sent TaskID(id) to BindServer");
624
} catch (IOException e) {
625
throw new Failure("Caught IOException while sending TaskID(id) to BindServer:\n\t"
626
+ e);
627
}
628
}
629
630
/**
631
* Check if thread is connected to <code>BindServer</code>.
632
*/
633
public boolean isConnected() {
634
return (connection != null && connection.isConnected());
635
}
636
637
/**
638
* Send a command to </code>BindServer</code>.
639
*/
640
public synchronized void sendCommand(Object command) throws IOException {
641
connection.writeObject(command);
642
}
643
644
/**
645
* Receive response from <code>BindServer</code>.
646
*/
647
public Object getReply() {
648
synchronized (replies) {
649
while (replies.isEmpty()) {
650
if (!isConnected()) {
651
throw new Failure("No reply from BindServer: connection lost");
652
}
653
try {
654
replies.wait(TRY_DELAY);
655
} catch (InterruptedException e) {
656
e.printStackTrace(getOutStream());
657
throw new Failure("Thread interrupted while waiting for reply from BindServer:\n\t"
658
+ e);
659
}
660
}
661
Object reply = replies.removeFirst();
662
if (reply == null) {
663
throw new Failure("No reply from BindServer: connection lost");
664
}
665
return reply;
666
}
667
}
668
669
/**
670
* Add response object to the list of received responses.
671
*/
672
private void addReply(BindServer.Response reply) {
673
synchronized (replies) {
674
replies.add(reply);
675
replies.notifyAll();
676
}
677
}
678
679
/**
680
* Read packets from <code>BindServer<code> connection and
681
* notify waiting thread if response or IOPipe message received.
682
* Received lines of redirected streams are put into log.
683
*/
684
public void run() {
685
trace(TRACE_LEVEL_THREADS, "BindServerListener thread started");
686
try {
687
for (;;) {
688
Object reply = connection.readObject();
689
if (reply == null) {
690
break;
691
} else if (reply instanceof BindServer.Disconnect) {
692
reply = null;
693
trace(TRACE_LEVEL_ACTIONS, "Packet is Disconnect: close connection");
694
break;
695
} else if (reply instanceof BindServer.RedirectedStream) {
696
BindServer.RedirectedStream castedReply = (BindServer.RedirectedStream)reply;
697
trace(TRACE_LEVEL_ACTIONS, "Packet is RedirectedStream: put message into log");
698
log.println(castedReply.line);
699
} else if (reply instanceof BindServer.Response) {
700
BindServer.Response castedReply = (BindServer.Response)reply;
701
trace(TRACE_LEVEL_ACTIONS, "Packet is reply: notify all threads waiting for reply");
702
addReply(castedReply);
703
} else {
704
trace(TRACE_LEVEL_ACTIONS, "Packet is unknown: throw Failure");
705
throw new Failure("Wrong reply from BindServer: " + reply);
706
}
707
}
708
} catch (Exception e) {
709
e.printStackTrace(getOutStream());
710
complain("Caught exception while reading packets from BindServer:\n\t" + e);
711
} finally {
712
closeConnection();
713
addReply(null);
714
trace(TRACE_LEVEL_THREADS, "BindServerListener thread finished");
715
}
716
}
717
718
/**
719
* Send Disconnect command to </code>BindServer</code>.
720
*/
721
public void disconnect() {
722
if (connection == null) return;
723
try {
724
sendCommand(new BindServer.Disconnect());
725
} catch (IOException e) {
726
display("Caught IOException while requesting disconnection with BindServer");
727
}
728
}
729
730
/**
731
* Close socket connection.
732
*/
733
public void closeConnection() {
734
if (connection != null) {
735
connection.close();
736
}
737
}
738
739
/**
740
* Wait for thread finished in the specified timeout or interrupt it.
741
*/
742
public void waitForThread(long millis) {
743
DebugeeBinder.waitForThread(this, millis, logger);
744
}
745
746
/**
747
* Close this thread by waiting for it finishes or interrupt it
748
* and close socket connection.
749
*/
750
public void close() {
751
disconnect();
752
waitForThread(DebugeeBinder.THREAD_TIMEOUT);
753
closeConnection();
754
}
755
756
} // BindServerListener
757
758
} // DebugeeBinder
759
760