Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/nio/channels/TestServers.java
38813 views
1
/*
2
* Copyright (c) 2012, 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
/* Test utility classes
25
*
26
*/
27
28
import java.io.*;
29
import java.net.*;
30
import java.util.ArrayList;
31
import java.util.Date;
32
import java.util.List;
33
34
35
public class TestServers {
36
37
private TestServers() { }
38
39
/**
40
* An abstract server identifies a server which listens on a port on on a
41
* given machine.
42
*/
43
static abstract class AbstractServer {
44
45
private AbstractServer() {
46
}
47
48
public abstract int getPort();
49
50
public abstract InetAddress getAddress();
51
}
52
53
/**
54
* A downgraded type of AbstractServer which will refuse connections. Note:
55
* use it once and throw it away - this implementation opens an anonymous
56
* socket and closes it, returning the address of the closed socket. If
57
* other servers are started afterwards, the address/port might get reused
58
* and become connectable again - so it's not a good idea to assume that
59
* connections using this address/port will always be refused. Connections
60
* will be refused as long as the address/port of the refusing server has
61
* not been reused.
62
*/
63
static class RefusingServer extends AbstractServer {
64
65
final InetAddress address;
66
final int port;
67
68
private RefusingServer(InetAddress address, int port) {
69
this.address = address;
70
this.port = port;
71
}
72
73
@Override
74
public int getPort() {
75
return port;
76
}
77
78
@Override
79
public InetAddress getAddress() {
80
return address;
81
}
82
83
public static RefusingServer startNewServer() throws IOException {
84
ServerSocket socket = new ServerSocket(0, 100,
85
InetAddress.getLocalHost());
86
RefusingServer server = new RefusingServer(socket.getInetAddress(),
87
socket.getLocalPort());
88
socket.close();
89
return server;
90
}
91
}
92
93
/**
94
* An abstract class for implementing small TCP servers for the nio tests
95
* purposes. Disclaimer: This is a naive implementation that uses the old
96
* networking APIs (not those from {@code java.nio.*}) and shamelessly
97
* extends/creates Threads instead of using an executor service.
98
*/
99
static abstract class AbstractTcpServer extends AbstractServer
100
implements Runnable, Closeable {
101
102
protected final long linger; // #of ms to wait before responding
103
private Thread acceptThread; // thread waiting for accept
104
// list of opened connections that should be closed on close.
105
private List<TcpConnectionThread> connections = new ArrayList<>();
106
private ServerSocket serverSocket; // the server socket
107
private boolean started = false; // whether the server is started
108
Throwable error = null;
109
110
/**
111
* Creates a new abstract TCP server.
112
*
113
* @param linger the amount of time the server should wait before
114
* responding to requests.
115
*/
116
protected AbstractTcpServer(long linger) {
117
this.linger = linger;
118
}
119
120
/**
121
* The local port to which the server is bound.
122
*
123
* @return The local port to which the server is bound.
124
* @exception IllegalStateException is thrown if the server is not
125
* started.
126
*/
127
@Override
128
public final synchronized int getPort() {
129
if (!started) {
130
throw new IllegalStateException("Not started");
131
}
132
return serverSocket.getLocalPort();
133
}
134
135
/**
136
* The local address to which the server is bound.
137
*
138
* @return The local address to which the server is bound.
139
* @exception IllegalStateException is thrown if the server is not
140
* started.
141
*/
142
@Override
143
public final synchronized InetAddress getAddress() {
144
if (!started) {
145
throw new IllegalStateException("Not started");
146
}
147
return serverSocket.getInetAddress();
148
}
149
150
/**
151
* Tells whether the server is started.
152
*
153
* @return true if the server is started.
154
*/
155
public final synchronized boolean isStarted() {
156
return started;
157
}
158
159
/**
160
* Creates a new server socket.
161
*
162
* @param port local port to bind to.
163
* @param backlog requested maximum length of the queue of incoming
164
* connections.
165
* @param address local address to bind to.
166
* @return a new bound server socket ready to accept connections.
167
* @throws IOException if the socket cannot be created or bound.
168
*/
169
protected ServerSocket newServerSocket(int port, int backlog,
170
InetAddress address)
171
throws IOException {
172
return new ServerSocket(port, backlog, address);
173
}
174
175
/**
176
* Starts listening for connections.
177
*
178
* @throws IOException if the server socket cannot be created or bound.
179
*/
180
public final synchronized void start() throws IOException {
181
if (started) {
182
return;
183
}
184
final ServerSocket socket =
185
newServerSocket(0, 100, InetAddress.getLocalHost());
186
serverSocket = socket;
187
acceptThread = new Thread(this);
188
acceptThread.setDaemon(true);
189
acceptThread.start();
190
started = true;
191
}
192
193
/**
194
* Calls {@code Thread.sleep(linger);}
195
*/
196
protected final void lingerIfRequired() {
197
if (linger > 0) {
198
try {
199
Thread.sleep(linger);
200
} catch (InterruptedException x) {
201
Thread.interrupted();
202
final ServerSocket socket = serverSocket();
203
if (socket != null && !socket.isClosed()) {
204
System.err.println("Thread interrupted...");
205
}
206
}
207
}
208
}
209
210
final synchronized ServerSocket serverSocket() {
211
return this.serverSocket;
212
}
213
214
/**
215
* The main accept loop.
216
*/
217
@Override
218
public final void run() {
219
final ServerSocket sSocket = serverSocket();
220
try {
221
Socket s;
222
while (isStarted() && !Thread.interrupted()
223
&& (s = sSocket.accept()) != null) {
224
lingerIfRequired();
225
listen(s);
226
}
227
} catch (Exception x) {
228
error = x;
229
} finally {
230
synchronized (this) {
231
if (!sSocket.isClosed()) {
232
try {
233
sSocket.close();
234
} catch (IOException x) {
235
System.err.println("Failed to close server socket");
236
}
237
}
238
if (started && this.serverSocket == sSocket) {
239
started = false;
240
this.serverSocket = null;
241
this.acceptThread = null;
242
}
243
}
244
}
245
}
246
247
/**
248
* Represents a connection accepted by the server.
249
*/
250
protected abstract class TcpConnectionThread extends Thread {
251
252
protected final Socket socket;
253
254
protected TcpConnectionThread(Socket socket) {
255
this.socket = socket;
256
this.setDaemon(true);
257
}
258
259
public void close() throws IOException {
260
socket.close();
261
interrupt();
262
}
263
}
264
265
/**
266
* Creates a new TcpConnnectionThread to handle the connection through
267
* an accepted socket.
268
*
269
* @param s the socket returned by {@code serverSocket.accept()}.
270
* @return a new TcpConnnectionThread to handle the connection through
271
* an accepted socket.
272
*/
273
protected abstract TcpConnectionThread createConnection(Socket s);
274
275
/**
276
* Creates and starts a new TcpConnectionThread to handle the accepted
277
* socket.
278
*
279
* @param s the socket returned by {@code serverSocket.accept()}.
280
*/
281
private synchronized void listen(Socket s) {
282
TcpConnectionThread c = createConnection(s);
283
c.start();
284
addConnection(c);
285
}
286
287
/**
288
* Add the connection to the list of accepted connections.
289
*
290
* @param connection an accepted connection.
291
*/
292
protected synchronized void addConnection(
293
TcpConnectionThread connection) {
294
connections.add(connection);
295
}
296
297
/**
298
* Remove the connection from the list of accepted connections.
299
*
300
* @param connection an accepted connection.
301
*/
302
protected synchronized void removeConnection(
303
TcpConnectionThread connection) {
304
connections.remove(connection);
305
}
306
307
/**
308
* Close the server socket and all the connections present in the list
309
* of accepted connections.
310
*
311
* @throws IOException
312
*/
313
@Override
314
public synchronized void close() throws IOException {
315
if (serverSocket != null && !serverSocket.isClosed()) {
316
serverSocket.close();
317
}
318
if (acceptThread != null) {
319
acceptThread.interrupt();
320
}
321
int failed = 0;
322
for (TcpConnectionThread c : connections) {
323
try {
324
c.close();
325
} catch (IOException x) {
326
// no matter - we're closing.
327
failed++;
328
}
329
}
330
connections.clear();
331
if (failed > 0) {
332
throw new IOException("Failed to close some connections");
333
}
334
}
335
}
336
337
/**
338
* A small TCP Server that emulates the echo service for tests purposes. See
339
* http://en.wikipedia.org/wiki/Echo_Protocol This server uses an anonymous
340
* port - NOT the standard port 7. We don't guarantee that its behavior
341
* exactly matches the RFC - the only purpose of this server is to have
342
* something that responds to nio tests...
343
*/
344
static final class EchoServer extends AbstractTcpServer {
345
346
public EchoServer() {
347
this(0L);
348
}
349
350
public EchoServer(long linger) {
351
super(linger);
352
}
353
354
@Override
355
protected TcpConnectionThread createConnection(Socket s) {
356
return new EchoConnection(s);
357
}
358
359
private final class EchoConnection extends TcpConnectionThread {
360
361
public EchoConnection(Socket socket) {
362
super(socket);
363
}
364
365
@Override
366
public void run() {
367
try {
368
final InputStream is = socket.getInputStream();
369
final OutputStream out = socket.getOutputStream();
370
byte[] b = new byte[255];
371
int n;
372
while ((n = is.read(b)) > 0) {
373
lingerIfRequired();
374
out.write(b, 0, n);
375
}
376
} catch (IOException io) {
377
// fall through to finally
378
} finally {
379
if (!socket.isClosed()) {
380
try {
381
socket.close();
382
} catch (IOException x) {
383
System.err.println(
384
"Failed to close echo connection socket");
385
}
386
}
387
removeConnection(this);
388
}
389
}
390
}
391
392
public static EchoServer startNewServer() throws IOException {
393
return startNewServer(0);
394
}
395
396
public static EchoServer startNewServer(long linger) throws IOException {
397
final EchoServer echoServer = new EchoServer(linger);
398
echoServer.start();
399
return echoServer;
400
}
401
}
402
403
/**
404
* A small TCP server that emulates the Day & Time service for tests
405
* purposes. See http://en.wikipedia.org/wiki/Daytime_Protocol This server
406
* uses an anonymous port - NOT the standard port 13. We don't guarantee
407
* that its behavior exactly matches the RFC - the only purpose of this
408
* server is to have something that responds to nio tests...
409
*/
410
static final class DayTimeServer extends AbstractTcpServer {
411
412
public DayTimeServer() {
413
this(0L);
414
}
415
416
public DayTimeServer(long linger) {
417
super(linger);
418
}
419
420
@Override
421
protected TcpConnectionThread createConnection(Socket s) {
422
return new DayTimeServerConnection(s);
423
}
424
425
@Override
426
protected void addConnection(TcpConnectionThread connection) {
427
// do nothing - the connection just write the date and terminates.
428
}
429
430
@Override
431
protected void removeConnection(TcpConnectionThread connection) {
432
// do nothing - we're not adding connections to the list...
433
}
434
435
private final class DayTimeServerConnection extends TcpConnectionThread {
436
437
public DayTimeServerConnection(Socket socket) {
438
super(socket);
439
}
440
441
@Override
442
public void run() {
443
try {
444
final OutputStream out = socket.getOutputStream();
445
lingerIfRequired();
446
out.write(new Date(System.currentTimeMillis())
447
.toString().getBytes("US-ASCII"));
448
out.flush();
449
} catch (IOException io) {
450
// fall through to finally
451
} finally {
452
if (!socket.isClosed()) {
453
try {
454
socket.close();
455
} catch (IOException x) {
456
System.err.println(
457
"Failed to close echo connection socket");
458
}
459
}
460
}
461
}
462
}
463
464
public static DayTimeServer startNewServer()
465
throws IOException {
466
return startNewServer(0);
467
}
468
469
public static DayTimeServer startNewServer(long linger)
470
throws IOException {
471
final DayTimeServer daytimeServer = new DayTimeServer(linger);
472
daytimeServer.start();
473
return daytimeServer;
474
}
475
}
476
477
/**
478
* An abstract class for implementing small UDP Servers for the nio tests
479
* purposes. Disclaimer: This is a naive implementation that uses the old
480
* networking APIs (not those from {@code java.nio.*}) and shamelessly
481
* extends/creates Threads instead of using an executor service.
482
*/
483
static abstract class AbstractUdpServer extends AbstractServer
484
implements Runnable, Closeable {
485
486
protected final long linger; // #of ms to wait before responding
487
private Thread acceptThread; // thread waiting for packets
488
private DatagramSocket serverSocket; // the server socket
489
private boolean started = false; // whether the server is started
490
Throwable error = null;
491
492
/**
493
* Creates a new abstract UDP server.
494
*
495
* @param linger the amount of time the server should wait before
496
* responding to requests.
497
*/
498
protected AbstractUdpServer(long linger) {
499
this.linger = linger;
500
}
501
502
/**
503
* The local port to which the server is bound.
504
*
505
* @return The local port to which the server is bound.
506
* @exception IllegalStateException is thrown if the server is not
507
* started.
508
*/
509
@Override
510
public final synchronized int getPort() {
511
if (!started) {
512
throw new IllegalStateException("Not started");
513
}
514
return serverSocket.getLocalPort();
515
}
516
517
/**
518
* The local address to which the server is bound.
519
*
520
* @return The local address to which the server is bound.
521
* @exception IllegalStateException is thrown if the server is not
522
* started.
523
*/
524
@Override
525
public final synchronized InetAddress getAddress() {
526
if (!started) {
527
throw new IllegalStateException("Not started");
528
}
529
return serverSocket.getLocalAddress();
530
}
531
532
/**
533
* Tells whether the server is started.
534
*
535
* @return true if the server is started.
536
*/
537
public final synchronized boolean isStarted() {
538
return started;
539
}
540
541
/**
542
* Creates a new datagram socket.
543
*
544
* @param port local port to bind to.
545
* @param address local address to bind to.
546
* @return a new bound server socket ready to listen for packets.
547
* @throws IOException if the socket cannot be created or bound.
548
*/
549
protected DatagramSocket newDatagramSocket(int port,
550
InetAddress address)
551
throws IOException {
552
return new DatagramSocket(port, address);
553
}
554
555
/**
556
* Starts listening for connections.
557
*
558
* @throws IOException if the server socket cannot be created or bound.
559
*/
560
public final synchronized void start() throws IOException {
561
if (started) {
562
return;
563
}
564
final DatagramSocket socket =
565
newDatagramSocket(0, InetAddress.getLocalHost());
566
serverSocket = socket;
567
acceptThread = new Thread(this);
568
acceptThread.setDaemon(true);
569
acceptThread.start();
570
started = true;
571
}
572
573
/**
574
* Calls {@code Thread.sleep(linger);}
575
*/
576
protected final void lingerIfRequired() {
577
if (linger > 0) {
578
try {
579
Thread.sleep(linger);
580
} catch (InterruptedException x) {
581
Thread.interrupted();
582
final DatagramSocket socket = serverSocket();
583
if (socket != null && !socket.isClosed()) {
584
System.err.println("Thread interrupted...");
585
}
586
}
587
}
588
}
589
590
final synchronized DatagramSocket serverSocket() {
591
return this.serverSocket;
592
}
593
594
final synchronized boolean send(DatagramSocket socket,
595
DatagramPacket response) throws IOException {
596
if (!socket.isClosed()) {
597
socket.send(response);
598
return true;
599
} else {
600
return false;
601
}
602
}
603
604
/**
605
* The main receive loop.
606
*/
607
@Override
608
public final void run() {
609
final DatagramSocket sSocket = serverSocket();
610
try {
611
final int size = Math.max(1024, sSocket.getReceiveBufferSize());
612
if (size > sSocket.getReceiveBufferSize()) {
613
sSocket.setReceiveBufferSize(size);
614
}
615
while (isStarted() && !Thread.interrupted() && !sSocket.isClosed()) {
616
final byte[] buf = new byte[size];
617
final DatagramPacket packet =
618
new DatagramPacket(buf, buf.length);
619
lingerIfRequired();
620
sSocket.receive(packet);
621
//System.out.println("Received packet from: "
622
// + packet.getAddress()+":"+packet.getPort());
623
handle(sSocket, packet);
624
}
625
} catch (Exception x) {
626
error = x;
627
} finally {
628
synchronized (this) {
629
if (!sSocket.isClosed()) {
630
sSocket.close();
631
}
632
if (started && this.serverSocket == sSocket) {
633
started = false;
634
this.serverSocket = null;
635
this.acceptThread = null;
636
}
637
}
638
}
639
}
640
641
/**
642
* Represents an UDP request received by the server.
643
*/
644
protected abstract class UdpRequestThread extends Thread {
645
646
protected final DatagramPacket request;
647
protected final DatagramSocket socket;
648
649
protected UdpRequestThread(DatagramSocket socket, DatagramPacket request) {
650
this.socket = socket;
651
this.request = request;
652
this.setDaemon(true);
653
}
654
}
655
656
/**
657
* Creates a new UdpRequestThread to handle a DatagramPacket received
658
* through a DatagramSocket.
659
*
660
* @param socket the socket through which the request was received.
661
* @param request the datagram packet received through the socket.
662
* @return a new UdpRequestThread to handle the request received through
663
* a DatagramSocket.
664
*/
665
protected abstract UdpRequestThread createConnection(DatagramSocket socket,
666
DatagramPacket request);
667
668
/**
669
* Creates and starts a new UdpRequestThread to handle the received
670
* datagram packet.
671
*
672
* @param socket the socket through which the request was received.
673
* @param request the datagram packet received through the socket.
674
*/
675
private synchronized void handle(DatagramSocket socket,
676
DatagramPacket request) {
677
UdpRequestThread c = createConnection(socket, request);
678
// c can be null if the request requires no response.
679
if (c != null) {
680
c.start();
681
}
682
}
683
684
/**
685
* Close the server socket.
686
*
687
* @throws IOException
688
*/
689
@Override
690
public synchronized void close() throws IOException {
691
if (serverSocket != null && !serverSocket.isClosed()) {
692
serverSocket.close();
693
}
694
if (acceptThread != null) {
695
acceptThread.interrupt();
696
}
697
}
698
}
699
700
/**
701
* A small UDP Server that emulates the discard service for tests purposes.
702
* See http://en.wikipedia.org/wiki/Discard_Protocol This server uses an
703
* anonymous port - NOT the standard port 9. We don't guarantee that its
704
* behavior exactly matches the RFC - the only purpose of this server is to
705
* have something that responds to nio tests...
706
*/
707
static final class UdpDiscardServer extends AbstractUdpServer {
708
709
public UdpDiscardServer() {
710
this(0L);
711
}
712
713
public UdpDiscardServer(long linger) {
714
super(linger);
715
}
716
717
@Override
718
protected UdpRequestThread createConnection(DatagramSocket socket,
719
DatagramPacket request) {
720
// no response required
721
return null;
722
}
723
724
public static UdpDiscardServer startNewServer() throws IOException {
725
return startNewServer(0);
726
}
727
728
public static UdpDiscardServer startNewServer(long linger) throws IOException {
729
final UdpDiscardServer discardServer = new UdpDiscardServer(linger);
730
discardServer.start();
731
return discardServer;
732
}
733
}
734
735
/**
736
* A small UDP Server that emulates the echo service for tests purposes. See
737
* http://en.wikipedia.org/wiki/Echo_Protocol This server uses an anonymous
738
* port - NOT the standard port 7. We don't guarantee that its behavior
739
* exactly matches the RFC - the only purpose of this server is to have
740
* something that responds to nio tests...
741
*/
742
static final class UdpEchoServer extends AbstractUdpServer {
743
744
public UdpEchoServer() {
745
this(0L);
746
}
747
748
public UdpEchoServer(long linger) {
749
super(linger);
750
}
751
752
@Override
753
protected UdpEchoRequest createConnection(DatagramSocket socket,
754
DatagramPacket request) {
755
return new UdpEchoRequest(socket, request);
756
}
757
758
private final class UdpEchoRequest extends UdpRequestThread {
759
760
public UdpEchoRequest(DatagramSocket socket, DatagramPacket request) {
761
super(socket, request);
762
}
763
764
@Override
765
public void run() {
766
try {
767
lingerIfRequired();
768
final DatagramPacket response =
769
new DatagramPacket(request.getData(),
770
request.getOffset(), request.getLength(),
771
request.getAddress(), request.getPort());
772
send(socket, response);
773
} catch (IOException io) {
774
System.err.println("Failed to send response: " + io);
775
io.printStackTrace(System.err);
776
}
777
}
778
}
779
780
public static UdpEchoServer startNewServer() throws IOException {
781
return startNewServer(0);
782
}
783
784
public static UdpEchoServer startNewServer(long linger) throws IOException {
785
final UdpEchoServer echoServer = new UdpEchoServer(linger);
786
echoServer.start();
787
return echoServer;
788
}
789
}
790
791
/**
792
* A small UDP server that emulates the Day & Time service for tests
793
* purposes. See http://en.wikipedia.org/wiki/Daytime_Protocol This server
794
* uses an anonymous port - NOT the standard port 13. We don't guarantee
795
* that its behavior exactly matches the RFC - the only purpose of this
796
* server is to have something that responds to nio tests...
797
*/
798
static final class UdpDayTimeServer extends AbstractUdpServer {
799
800
public UdpDayTimeServer() {
801
this(0L);
802
}
803
804
public UdpDayTimeServer(long linger) {
805
super(linger);
806
}
807
808
@Override
809
protected UdpDayTimeRequestThread createConnection(DatagramSocket socket,
810
DatagramPacket request) {
811
return new UdpDayTimeRequestThread(socket, request);
812
}
813
814
private final class UdpDayTimeRequestThread extends UdpRequestThread {
815
816
public UdpDayTimeRequestThread(DatagramSocket socket,
817
DatagramPacket request) {
818
super(socket, request);
819
}
820
821
@Override
822
public void run() {
823
try {
824
lingerIfRequired();
825
final byte[] data = new Date(System.currentTimeMillis())
826
.toString().getBytes("US-ASCII");
827
final DatagramPacket response =
828
new DatagramPacket(data, 0, data.length,
829
request.getAddress(), request.getPort());
830
send(socket, response);
831
} catch (IOException io) {
832
System.err.println("Failed to send response: " + io);
833
io.printStackTrace(System.err);
834
}
835
}
836
}
837
838
public static UdpDayTimeServer startNewServer() throws IOException {
839
return startNewServer(0);
840
}
841
842
public static UdpDayTimeServer startNewServer(long linger)
843
throws IOException {
844
final UdpDayTimeServer echoServer = new UdpDayTimeServer(linger);
845
echoServer.start();
846
return echoServer;
847
}
848
}
849
}
850
851