Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
41159 views
1
/*
2
* Copyright (c) 2000, 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.nio.ch;
27
28
import java.io.FileDescriptor;
29
import java.io.IOException;
30
import java.net.BindException;
31
import java.net.InetSocketAddress;
32
import java.net.ProtocolFamily;
33
import java.net.ServerSocket;
34
import java.net.SocketAddress;
35
import java.net.SocketOption;
36
import java.net.SocketTimeoutException;
37
import java.net.StandardSocketOptions;
38
import java.net.UnixDomainSocketAddress;
39
import java.nio.channels.AlreadyBoundException;
40
import java.nio.channels.AsynchronousCloseException;
41
import java.nio.channels.ClosedChannelException;
42
import java.nio.channels.IllegalBlockingModeException;
43
import java.nio.channels.NotYetBoundException;
44
import java.nio.channels.SelectionKey;
45
import java.nio.channels.ServerSocketChannel;
46
import java.nio.channels.SocketChannel;
47
import java.nio.channels.spi.SelectorProvider;
48
import java.nio.file.Path;
49
import java.util.Collections;
50
import java.util.HashSet;
51
import java.util.Set;
52
import java.util.Objects;
53
import java.util.concurrent.locks.ReentrantLock;
54
import static java.net.StandardProtocolFamily.INET;
55
import static java.net.StandardProtocolFamily.INET6;
56
import static java.net.StandardProtocolFamily.UNIX;
57
58
import sun.net.NetHooks;
59
import sun.net.ext.ExtendedSocketOptions;
60
61
/**
62
* An implementation of ServerSocketChannels
63
*/
64
65
class ServerSocketChannelImpl
66
extends ServerSocketChannel
67
implements SelChImpl
68
{
69
// Used to make native close and configure calls
70
private static final NativeDispatcher nd = new SocketDispatcher();
71
72
// The protocol family of the socket
73
private final ProtocolFamily family;
74
75
// Our file descriptor
76
private final FileDescriptor fd;
77
private final int fdVal;
78
79
// Lock held by thread currently blocked on this channel
80
private final ReentrantLock acceptLock = new ReentrantLock();
81
82
// Lock held by any thread that modifies the state fields declared below
83
// DO NOT invoke a blocking I/O operation while holding this lock!
84
private final Object stateLock = new Object();
85
86
// -- The following fields are protected by stateLock
87
88
// Channel state, increases monotonically
89
private static final int ST_INUSE = 0;
90
private static final int ST_CLOSING = 1;
91
private static final int ST_CLOSED = 2;
92
private int state;
93
94
// ID of native thread currently blocked in this channel, for signalling
95
private long thread;
96
97
// Binding
98
private SocketAddress localAddress; // null => unbound
99
100
// set true when exclusive binding is on and SO_REUSEADDR is emulated
101
private boolean isReuseAddress;
102
103
// Our socket adaptor, if any
104
private ServerSocket socket;
105
106
// -- End of fields protected by stateLock
107
108
ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
109
this(sp, Net.isIPv6Available() ? INET6 : INET);
110
}
111
112
ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family)
113
throws IOException
114
{
115
super(sp);
116
Objects.requireNonNull(family, "'family' is null");
117
if ((family != INET) && (family != INET6) && (family != UNIX)) {
118
throw new UnsupportedOperationException("Protocol family not supported");
119
}
120
if (family == INET6 && !Net.isIPv6Available()) {
121
throw new UnsupportedOperationException("IPv6 not available");
122
}
123
124
this.family = family;
125
if (family == UNIX) {
126
this.fd = UnixDomainSockets.socket();
127
} else {
128
this.fd = Net.serverSocket(family, true);
129
}
130
this.fdVal = IOUtil.fdVal(fd);
131
}
132
133
ServerSocketChannelImpl(SelectorProvider sp,
134
ProtocolFamily family,
135
FileDescriptor fd,
136
boolean bound)
137
throws IOException
138
{
139
super(sp);
140
141
if (family == UNIX) {
142
this.family = UNIX;
143
} else {
144
this.family = Net.isIPv6Available() ? INET6 : INET;
145
}
146
this.fd = fd;
147
this.fdVal = IOUtil.fdVal(fd);
148
149
if (bound) {
150
synchronized (stateLock) {
151
if (family == UNIX) {
152
localAddress = UnixDomainSockets.localAddress(fd);
153
} else {
154
localAddress = Net.localAddress(fd);
155
}
156
}
157
}
158
}
159
160
/**
161
* Returns true if this channel is to a INET or INET6 socket.
162
*/
163
private boolean isNetSocket() {
164
return (family == INET) || (family == INET6);
165
}
166
167
/**
168
* Returns true if this channel is to a UNIX socket.
169
*/
170
boolean isUnixSocket() {
171
return (family == UNIX);
172
}
173
174
// @throws ClosedChannelException if channel is closed
175
private void ensureOpen() throws ClosedChannelException {
176
if (!isOpen())
177
throw new ClosedChannelException();
178
}
179
180
@Override
181
public ServerSocket socket() {
182
synchronized (stateLock) {
183
if (socket == null) {
184
if (isNetSocket()) {
185
socket = ServerSocketAdaptor.create(this);
186
} else {
187
throw new UnsupportedOperationException("Not supported");
188
}
189
}
190
return socket;
191
}
192
}
193
194
@Override
195
public SocketAddress getLocalAddress() throws IOException {
196
synchronized (stateLock) {
197
ensureOpen();
198
if (isUnixSocket()) {
199
return UnixDomainSockets.getRevealedLocalAddress(localAddress);
200
} else {
201
return Net.getRevealedLocalAddress(localAddress);
202
}
203
}
204
}
205
206
@Override
207
public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
208
throws IOException
209
{
210
Objects.requireNonNull(name);
211
if (!supportedOptions().contains(name))
212
throw new UnsupportedOperationException("'" + name + "' not supported");
213
if (!name.type().isInstance(value))
214
throw new IllegalArgumentException("Invalid value '" + value + "'");
215
216
synchronized (stateLock) {
217
ensureOpen();
218
if (isNetSocket()
219
&& name == StandardSocketOptions.SO_REUSEADDR
220
&& Net.useExclusiveBind()) {
221
// SO_REUSEADDR emulated when using exclusive bind
222
isReuseAddress = (Boolean) value;
223
} else {
224
// no options that require special handling
225
Net.setSocketOption(fd, Net.UNSPEC, name, value);
226
}
227
return this;
228
}
229
}
230
231
@Override
232
@SuppressWarnings("unchecked")
233
public <T> T getOption(SocketOption<T> name)
234
throws IOException
235
{
236
Objects.requireNonNull(name);
237
if (!supportedOptions().contains(name))
238
throw new UnsupportedOperationException("'" + name + "' not supported");
239
240
synchronized (stateLock) {
241
ensureOpen();
242
if (isNetSocket()
243
&& name == StandardSocketOptions.SO_REUSEADDR
244
&& Net.useExclusiveBind()) {
245
// SO_REUSEADDR emulated when using exclusive bind
246
return (T) Boolean.valueOf(isReuseAddress);
247
} else {
248
// no options that require special handling
249
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
250
}
251
}
252
}
253
254
private static class DefaultOptionsHolder {
255
static final Set<SocketOption<?>> defaultInetOptions = defaultInetOptions();
256
static final Set<SocketOption<?>> defaultUnixDomainOptions = defaultUnixDomainOptions();
257
258
private static Set<SocketOption<?>> defaultInetOptions() {
259
HashSet<SocketOption<?>> set = new HashSet<>();
260
set.add(StandardSocketOptions.SO_RCVBUF);
261
set.add(StandardSocketOptions.SO_REUSEADDR);
262
if (Net.isReusePortAvailable()) {
263
set.add(StandardSocketOptions.SO_REUSEPORT);
264
}
265
set.addAll(ExtendedSocketOptions.serverSocketOptions());
266
return Collections.unmodifiableSet(set);
267
}
268
269
private static Set<SocketOption<?>> defaultUnixDomainOptions() {
270
HashSet<SocketOption<?>> set = new HashSet<>();
271
set.add(StandardSocketOptions.SO_RCVBUF);
272
return Collections.unmodifiableSet(set);
273
}
274
}
275
276
@Override
277
public final Set<SocketOption<?>> supportedOptions() {
278
if (isUnixSocket()) {
279
return DefaultOptionsHolder.defaultUnixDomainOptions;
280
} else {
281
return DefaultOptionsHolder.defaultInetOptions;
282
}
283
}
284
285
@Override
286
public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
287
synchronized (stateLock) {
288
ensureOpen();
289
if (localAddress != null)
290
throw new AlreadyBoundException();
291
if (isUnixSocket()) {
292
localAddress = unixBind(local, backlog);
293
} else {
294
localAddress = netBind(local, backlog);
295
}
296
}
297
return this;
298
}
299
300
private SocketAddress unixBind(SocketAddress local, int backlog) throws IOException {
301
UnixDomainSockets.checkPermission();
302
if (local == null) {
303
// Attempt up to 10 times to find an unused name in temp directory.
304
// If local address supplied then bind called only once
305
boolean bound = false;
306
int attempts = 0;
307
while (attempts < 10 && !bound) {
308
try {
309
Path path = UnixDomainSockets.generateTempName().getPath();
310
UnixDomainSockets.bind(fd, path);
311
bound = true;
312
} catch (BindException e) { }
313
attempts++;
314
}
315
if (!bound)
316
throw new BindException("Could not bind to temporary name");
317
} else {
318
Path path = UnixDomainSockets.checkAddress(local).getPath();
319
UnixDomainSockets.bind(fd, path);
320
}
321
Net.listen(fd, backlog < 1 ? 50 : backlog);
322
return UnixDomainSockets.localAddress(fd);
323
}
324
325
private SocketAddress netBind(SocketAddress local, int backlog) throws IOException {
326
InetSocketAddress isa;
327
if (local == null) {
328
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
329
} else {
330
isa = Net.checkAddress(local, family);
331
}
332
@SuppressWarnings("removal")
333
SecurityManager sm = System.getSecurityManager();
334
if (sm != null)
335
sm.checkListen(isa.getPort());
336
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
337
Net.bind(family, fd, isa.getAddress(), isa.getPort());
338
Net.listen(fd, backlog < 1 ? 50 : backlog);
339
return Net.localAddress(fd);
340
}
341
342
/**
343
* Marks the beginning of an I/O operation that might block.
344
*
345
* @throws ClosedChannelException if the channel is closed
346
* @throws NotYetBoundException if the channel's socket has not been bound yet
347
*/
348
private void begin(boolean blocking) throws ClosedChannelException {
349
if (blocking)
350
begin(); // set blocker to close channel if interrupted
351
synchronized (stateLock) {
352
ensureOpen();
353
if (localAddress == null)
354
throw new NotYetBoundException();
355
if (blocking)
356
thread = NativeThread.current();
357
}
358
}
359
360
/**
361
* Marks the end of an I/O operation that may have blocked.
362
*
363
* @throws AsynchronousCloseException if the channel was closed due to this
364
* thread being interrupted on a blocking I/O operation.
365
*/
366
private void end(boolean blocking, boolean completed)
367
throws AsynchronousCloseException
368
{
369
if (blocking) {
370
synchronized (stateLock) {
371
thread = 0;
372
if (state == ST_CLOSING) {
373
tryFinishClose();
374
}
375
}
376
end(completed);
377
}
378
}
379
380
@Override
381
public SocketChannel accept() throws IOException {
382
int n = 0;
383
FileDescriptor newfd = new FileDescriptor();
384
SocketAddress[] saa = new SocketAddress[1];
385
386
acceptLock.lock();
387
try {
388
boolean blocking = isBlocking();
389
try {
390
begin(blocking);
391
n = implAccept(this.fd, newfd, saa);
392
if (blocking) {
393
while (IOStatus.okayToRetry(n) && isOpen()) {
394
park(Net.POLLIN);
395
n = implAccept(this.fd, newfd, saa);
396
}
397
}
398
} finally {
399
end(blocking, n > 0);
400
assert IOStatus.check(n);
401
}
402
} finally {
403
acceptLock.unlock();
404
}
405
406
if (n > 0) {
407
return finishAccept(newfd, saa[0]);
408
} else {
409
return null;
410
}
411
}
412
413
private int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] saa)
414
throws IOException
415
{
416
if (isUnixSocket()) {
417
UnixDomainSockets.checkPermission();
418
String[] pa = new String[1];
419
int n = UnixDomainSockets.accept(fd, newfd, pa);
420
if (n > 0)
421
saa[0] = UnixDomainSocketAddress.of(pa[0]);
422
return n;
423
} else {
424
InetSocketAddress[] issa = new InetSocketAddress[1];
425
int n = Net.accept(fd, newfd, issa);
426
if (n > 0)
427
saa[0] = issa[0];
428
return n;
429
}
430
}
431
432
/**
433
* Accepts a new connection with a given timeout. This method requires the
434
* channel to be configured in blocking mode.
435
*
436
* @apiNote This method is for use by the socket adaptor.
437
*
438
* @param nanos the timeout, in nanoseconds
439
* @throws IllegalBlockingModeException if the channel is configured non-blocking
440
* @throws SocketTimeoutException if the timeout expires
441
*/
442
SocketChannel blockingAccept(long nanos) throws IOException {
443
int n = 0;
444
FileDescriptor newfd = new FileDescriptor();
445
SocketAddress[] saa = new SocketAddress[1];
446
447
acceptLock.lock();
448
try {
449
// check that channel is configured blocking
450
if (!isBlocking())
451
throw new IllegalBlockingModeException();
452
453
try {
454
begin(true);
455
// change socket to non-blocking
456
lockedConfigureBlocking(false);
457
try {
458
long startNanos = System.nanoTime();
459
n = implAccept(fd, newfd, saa);
460
while (n == IOStatus.UNAVAILABLE && isOpen()) {
461
long remainingNanos = nanos - (System.nanoTime() - startNanos);
462
if (remainingNanos <= 0) {
463
throw new SocketTimeoutException("Accept timed out");
464
}
465
park(Net.POLLIN, remainingNanos);
466
n = implAccept(fd, newfd, saa);
467
}
468
} finally {
469
// restore socket to blocking mode (if channel is open)
470
tryLockedConfigureBlocking(true);
471
}
472
} finally {
473
end(true, n > 0);
474
}
475
} finally {
476
acceptLock.unlock();
477
}
478
479
assert n > 0;
480
return finishAccept(newfd, saa[0]);
481
}
482
483
private SocketChannel finishAccept(FileDescriptor newfd, SocketAddress sa)
484
throws IOException
485
{
486
try {
487
// newly accepted socket is initially in blocking mode
488
IOUtil.configureBlocking(newfd, true);
489
490
// check permitted to accept connections from the remote address
491
if (isNetSocket()) {
492
@SuppressWarnings("removal")
493
SecurityManager sm = System.getSecurityManager();
494
if (sm != null) {
495
InetSocketAddress isa = (InetSocketAddress) sa;
496
sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
497
}
498
}
499
return new SocketChannelImpl(provider(), family, newfd, sa);
500
} catch (Exception e) {
501
nd.close(newfd);
502
throw e;
503
}
504
}
505
506
@Override
507
protected void implConfigureBlocking(boolean block) throws IOException {
508
acceptLock.lock();
509
try {
510
lockedConfigureBlocking(block);
511
} finally {
512
acceptLock.unlock();
513
}
514
}
515
516
/**
517
* Adjust the blocking. acceptLock must already be held.
518
*/
519
private void lockedConfigureBlocking(boolean block) throws IOException {
520
assert acceptLock.isHeldByCurrentThread();
521
synchronized (stateLock) {
522
ensureOpen();
523
IOUtil.configureBlocking(fd, block);
524
}
525
}
526
527
/**
528
* Adjusts the blocking mode if the channel is open. acceptLock must already
529
* be held.
530
*
531
* @return {@code true} if the blocking mode was adjusted, {@code false} if
532
* the blocking mode was not adjusted because the channel is closed
533
*/
534
private boolean tryLockedConfigureBlocking(boolean block) throws IOException {
535
assert acceptLock.isHeldByCurrentThread();
536
synchronized (stateLock) {
537
if (isOpen()) {
538
IOUtil.configureBlocking(fd, block);
539
return true;
540
} else {
541
return false;
542
}
543
}
544
}
545
546
/**
547
* Closes the socket if there are no accept in progress and the channel is
548
* not registered with a Selector.
549
*/
550
private boolean tryClose() throws IOException {
551
assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
552
if ((thread == 0) && !isRegistered()) {
553
state = ST_CLOSED;
554
nd.close(fd);
555
return true;
556
} else {
557
return false;
558
}
559
}
560
561
/**
562
* Invokes tryClose to attempt to close the socket.
563
*
564
* This method is used for deferred closing by I/O and Selector operations.
565
*/
566
private void tryFinishClose() {
567
try {
568
tryClose();
569
} catch (IOException ignore) { }
570
}
571
572
/**
573
* Closes this channel when configured in blocking mode.
574
*
575
* If there is an accept in progress then the socket is pre-closed and the
576
* accept thread is signalled, in which case the final close is deferred
577
* until the accept aborts.
578
*/
579
private void implCloseBlockingMode() throws IOException {
580
synchronized (stateLock) {
581
assert state < ST_CLOSING;
582
state = ST_CLOSING;
583
if (!tryClose()) {
584
long th = thread;
585
if (th != 0) {
586
nd.preClose(fd);
587
NativeThread.signal(th);
588
}
589
}
590
}
591
}
592
593
/**
594
* Closes this channel when configured in non-blocking mode.
595
*
596
* If the channel is registered with a Selector then the close is deferred
597
* until the channel is flushed from all Selectors.
598
*/
599
private void implCloseNonBlockingMode() throws IOException {
600
synchronized (stateLock) {
601
assert state < ST_CLOSING;
602
state = ST_CLOSING;
603
}
604
// wait for any accept to complete before trying to close
605
acceptLock.lock();
606
acceptLock.unlock();
607
synchronized (stateLock) {
608
if (state == ST_CLOSING) {
609
tryClose();
610
}
611
}
612
}
613
614
/**
615
* Invoked by implCloseChannel to close the channel.
616
*/
617
@Override
618
protected void implCloseSelectableChannel() throws IOException {
619
assert !isOpen();
620
if (isBlocking()) {
621
implCloseBlockingMode();
622
} else {
623
implCloseNonBlockingMode();
624
}
625
}
626
627
@Override
628
public void kill() {
629
synchronized (stateLock) {
630
if (state == ST_CLOSING) {
631
tryFinishClose();
632
}
633
}
634
}
635
636
/**
637
* Returns true if channel's socket is bound
638
*/
639
boolean isBound() {
640
synchronized (stateLock) {
641
return localAddress != null;
642
}
643
}
644
645
/**
646
* Returns the local address, or null if not bound
647
*/
648
SocketAddress localAddress() {
649
synchronized (stateLock) {
650
return localAddress;
651
}
652
}
653
654
/**
655
* Translates native poll revent set into a ready operation set
656
*/
657
public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
658
int intOps = ski.nioInterestOps();
659
int oldOps = ski.nioReadyOps();
660
int newOps = initialOps;
661
662
if ((ops & Net.POLLNVAL) != 0) {
663
// This should only happen if this channel is pre-closed while a
664
// selection operation is in progress
665
// ## Throw an error if this channel has not been pre-closed
666
return false;
667
}
668
669
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
670
newOps = intOps;
671
ski.nioReadyOps(newOps);
672
return (newOps & ~oldOps) != 0;
673
}
674
675
if (((ops & Net.POLLIN) != 0) &&
676
((intOps & SelectionKey.OP_ACCEPT) != 0))
677
newOps |= SelectionKey.OP_ACCEPT;
678
679
ski.nioReadyOps(newOps);
680
return (newOps & ~oldOps) != 0;
681
}
682
683
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
684
return translateReadyOps(ops, ski.nioReadyOps(), ski);
685
}
686
687
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
688
return translateReadyOps(ops, 0, ski);
689
}
690
691
/**
692
* Translates an interest operation set into a native poll event set
693
*/
694
public int translateInterestOps(int ops) {
695
int newOps = 0;
696
if ((ops & SelectionKey.OP_ACCEPT) != 0)
697
newOps |= Net.POLLIN;
698
return newOps;
699
}
700
701
public FileDescriptor getFD() {
702
return fd;
703
}
704
705
public int getFDVal() {
706
return fdVal;
707
}
708
709
public String toString() {
710
StringBuilder sb = new StringBuilder();
711
sb.append(this.getClass().getName());
712
sb.append('[');
713
if (!isOpen()) {
714
sb.append("closed");
715
} else {
716
synchronized (stateLock) {
717
SocketAddress addr = localAddress;
718
if (addr == null) {
719
sb.append("unbound");
720
} else if (isUnixSocket()) {
721
sb.append(UnixDomainSockets.getRevealedLocalAddressAsString(addr));
722
} else {
723
sb.append(Net.getRevealedLocalAddressAsString(addr));
724
}
725
}
726
}
727
sb.append(']');
728
return sb.toString();
729
}
730
}
731
732