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     // lazily set to true when the socket is configured non-blocking
107     private volatile boolean nonBlocking;
108 
109     // -- End of fields protected by stateLock
110 
111     ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
112         this(sp, Net.isIPv6Available() ? INET6 : INET);
113     }
114 
115     ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family)
116         throws IOException
117     {
118         super(sp);
119         Objects.requireNonNull(family, "'family' is null");
120         if ((family != INET) && (family != INET6) && (family != UNIX)) {
121             throw new UnsupportedOperationException("Protocol family not supported");
122         }
123         if (family == INET6 && !Net.isIPv6Available()) {
124             throw new UnsupportedOperationException("IPv6 not available");
125         }
126 
127         this.family = family;
128         if (family == UNIX) {
129             this.fd = UnixDomainSockets.socket();
130         } else {
131             this.fd = Net.serverSocket(family, true);
132         }
133         this.fdVal = IOUtil.fdVal(fd);
134     }
135 
136     ServerSocketChannelImpl(SelectorProvider sp,
137                             ProtocolFamily family,
138                             FileDescriptor fd,
139                             boolean bound)
140         throws IOException
141     {
142         super(sp);
143 
144         if (family == UNIX) {
145             this.family = UNIX;
146         } else {
147             this.family = Net.isIPv6Available() ? INET6 : INET;
148         }
149         this.fd = fd;
150         this.fdVal = IOUtil.fdVal(fd);
151 
152         if (bound) {
153             synchronized (stateLock) {
154                 if (family == UNIX) {
155                     localAddress = UnixDomainSockets.localAddress(fd);
156                 } else {
157                     localAddress = Net.localAddress(fd);
158                 }
159             }
160         }
161     }
162 
163     /**
164      * Returns true if this channel is to a INET or INET6 socket.
165      */
166     private boolean isNetSocket() {
167         return (family == INET) || (family == INET6);
168     }
169 
170     /**
171      * Returns true if this channel is to a UNIX socket.
172      */
173     boolean isUnixSocket() {
174         return (family == UNIX);
175     }
176 
177     // @throws ClosedChannelException if channel is closed
178     private void ensureOpen() throws ClosedChannelException {
179         if (!isOpen())
180             throw new ClosedChannelException();
181     }
182 
183     @Override
184     public ServerSocket socket() {
185         synchronized (stateLock) {
186             if (socket == null) {
187                 if (isNetSocket()) {
188                     socket = ServerSocketAdaptor.create(this);
189                 } else {
190                     throw new UnsupportedOperationException("Not supported");
191                 }
192             }
193             return socket;
194         }
195     }
196 
197     @Override
198     public SocketAddress getLocalAddress() throws IOException {
199         synchronized (stateLock) {
200             ensureOpen();
201             if (isUnixSocket()) {
202                 return UnixDomainSockets.getRevealedLocalAddress(localAddress);
203             } else {
204                 return Net.getRevealedLocalAddress(localAddress);
205             }
206         }
207     }
208 
209     @Override
210     public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
211         throws IOException
212     {
213         Objects.requireNonNull(name);
214         if (!supportedOptions().contains(name))
215             throw new UnsupportedOperationException("'" + name + "' not supported");
216         if (!name.type().isInstance(value))
217             throw new IllegalArgumentException("Invalid value '" + value + "'");
218 
219         synchronized (stateLock) {
220             ensureOpen();
221             if (isNetSocket()
222                     && name == StandardSocketOptions.SO_REUSEADDR
223                     && Net.useExclusiveBind()) {
224                 // SO_REUSEADDR emulated when using exclusive bind
225                 isReuseAddress = (Boolean) value;
226             } else {
227                 // no options that require special handling
228                 Net.setSocketOption(fd, Net.UNSPEC, name, value);
229             }
230             return this;
231         }
232     }
233 
234     @Override
235     @SuppressWarnings("unchecked")
236     public <T> T getOption(SocketOption<T> name)
237         throws IOException
238     {
239         Objects.requireNonNull(name);
240         if (!supportedOptions().contains(name))
241             throw new UnsupportedOperationException("'" + name + "' not supported");
242 
243         synchronized (stateLock) {
244             ensureOpen();
245             if (isNetSocket()
246                     && name == StandardSocketOptions.SO_REUSEADDR
247                     && Net.useExclusiveBind()) {
248                 // SO_REUSEADDR emulated when using exclusive bind
249                 return (T) Boolean.valueOf(isReuseAddress);
250             } else {
251                 // no options that require special handling
252                 return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
253             }
254         }
255     }
256 
257     private static class DefaultOptionsHolder {
258         static final Set<SocketOption<?>> defaultInetOptions = defaultInetOptions();
259         static final Set<SocketOption<?>> defaultUnixDomainOptions = defaultUnixDomainOptions();
260 
261         private static Set<SocketOption<?>> defaultInetOptions() {
262             HashSet<SocketOption<?>> set = new HashSet<>();
263             set.add(StandardSocketOptions.SO_RCVBUF);
264             set.add(StandardSocketOptions.SO_REUSEADDR);
265             if (Net.isReusePortAvailable()) {
266                 set.add(StandardSocketOptions.SO_REUSEPORT);
267             }
268             set.addAll(ExtendedSocketOptions.serverSocketOptions());
269             return Collections.unmodifiableSet(set);
270         }
271 
272         private static Set<SocketOption<?>> defaultUnixDomainOptions() {
273             HashSet<SocketOption<?>> set = new HashSet<>();
274             set.add(StandardSocketOptions.SO_RCVBUF);
275             return Collections.unmodifiableSet(set);
276         }
277     }
278 
279     @Override
280     public final Set<SocketOption<?>> supportedOptions() {
281         if (isUnixSocket()) {
282             return DefaultOptionsHolder.defaultUnixDomainOptions;
283         } else {
284             return DefaultOptionsHolder.defaultInetOptions;
285         }
286     }
287 
288     @Override
289     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
290         synchronized (stateLock) {
291             ensureOpen();
292             if (localAddress != null)
293                 throw new AlreadyBoundException();
294             if (isUnixSocket()) {
295                 localAddress = unixBind(local, backlog);
296             } else {
297                 localAddress = netBind(local, backlog);
298             }
299         }
300         return this;
301     }
302 
303     private SocketAddress unixBind(SocketAddress local, int backlog) throws IOException {
304         UnixDomainSockets.checkPermission();
305         if (local == null) {
306             // Attempt up to 10 times to find an unused name in temp directory.
307             // If local address supplied then bind called only once
308             boolean bound = false;
309             int attempts = 0;
310             while (attempts < 10 && !bound) {
311                 try {
312                     Path path = UnixDomainSockets.generateTempName().getPath();
313                     UnixDomainSockets.bind(fd, path);
314                     bound = true;
315                 } catch (BindException e) { }
316                 attempts++;
317             }
318             if (!bound)
319                 throw new BindException("Could not bind to temporary name");
320         } else {
321             Path path = UnixDomainSockets.checkAddress(local).getPath();
322             UnixDomainSockets.bind(fd, path);
323         }
324         Net.listen(fd, backlog < 1 ? 50 : backlog);
325         return UnixDomainSockets.localAddress(fd);
326     }
327 
328     private SocketAddress netBind(SocketAddress local, int backlog) throws IOException {
329         InetSocketAddress isa;
330         if (local == null) {
331             isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
332         } else {
333             isa = Net.checkAddress(local, family);
334         }
335         @SuppressWarnings("removal")
336         SecurityManager sm = System.getSecurityManager();
337         if (sm != null)
338             sm.checkListen(isa.getPort());
339         NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
340         Net.bind(family, fd, isa.getAddress(), isa.getPort());
341         Net.listen(fd, backlog < 1 ? 50 : backlog);
342         return Net.localAddress(fd);
343     }
344 
345     /**
346      * Marks the beginning of an I/O operation that might block.
347      *
348      * @throws ClosedChannelException if the channel is closed
349      * @throws NotYetBoundException if the channel's socket has not been bound yet
350      */
351     private void begin(boolean blocking) throws ClosedChannelException {
352         if (blocking)
353             begin();  // set blocker to close channel if interrupted
354         synchronized (stateLock) {
355             ensureOpen();
356             if (localAddress == null)
357                 throw new NotYetBoundException();
358             if (blocking)
359                 thread = NativeThread.current();
360         }
361     }
362 
363     /**
364      * Marks the end of an I/O operation that may have blocked.
365      *
366      * @throws AsynchronousCloseException if the channel was closed due to this
367      * thread being interrupted on a blocking I/O operation.
368      */
369     private void end(boolean blocking, boolean completed)
370         throws AsynchronousCloseException
371     {
372         if (blocking) {
373             synchronized (stateLock) {
374                 thread = 0;
375                 if (state == ST_CLOSING) {
376                     tryFinishClose();
377                 }
378             }
379             end(completed);
380         }
381     }
382 
383     @Override
384     public SocketChannel accept() throws IOException {
385         int n = 0;
386         FileDescriptor newfd = new FileDescriptor();
387         SocketAddress[] saa = new SocketAddress[1];
388 
389         acceptLock.lock();
390         try {
391             boolean blocking = isBlocking();
392             try {
393                 begin(blocking);
394                 lockedConfigureNonBlockingIfNeeded();
395                 n = implAccept(this.fd, newfd, saa);
396                 if (blocking) {
397                     while (IOStatus.okayToRetry(n) && isOpen()) {
398                         park(Net.POLLIN);
399                         n = implAccept(this.fd, newfd, saa);
400                     }
401                 }
402             } finally {
403                 end(blocking, n > 0);
404                 assert IOStatus.check(n);
405             }
406         } finally {
407             acceptLock.unlock();
408         }
409 
410         if (n > 0) {
411             return finishAccept(newfd, saa[0]);
412         } else {
413             return null;
414         }
415     }
416 
417     private int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] saa)
418         throws IOException
419     {
420         if (isUnixSocket()) {
421             UnixDomainSockets.checkPermission();
422             String[] pa = new String[1];
423             int n = UnixDomainSockets.accept(fd, newfd, pa);
424             if (n > 0)
425                 saa[0] = UnixDomainSocketAddress.of(pa[0]);
426             return n;
427         } else {
428             InetSocketAddress[] issa = new InetSocketAddress[1];
429             int n = Net.accept(fd, newfd, issa);
430             if (n > 0)
431                 saa[0] = issa[0];
432             return n;
433         }
434     }
435 
436     /**
437      * Accepts a new connection with a given timeout. This method requires the
438      * channel to be configured in blocking mode.
439      *
440      * @apiNote This method is for use by the socket adaptor.
441      *
442      * @param nanos the timeout, in nanoseconds
443      * @throws IllegalBlockingModeException if the channel is configured non-blocking
444      * @throws SocketTimeoutException if the timeout expires
445      */
446     SocketChannel blockingAccept(long nanos) throws IOException {
447         int n = 0;
448         FileDescriptor newfd = new FileDescriptor();
449         SocketAddress[] saa = new SocketAddress[1];
450 
451         acceptLock.lock();
452         try {
453             // check that channel is configured blocking
454             if (!isBlocking())
455                 throw new IllegalBlockingModeException();
456 
457             try {
458                 begin(true);
459                 // change socket to non-blocking
460                 lockedConfigureBlocking(false);
461                 try {
462                     long startNanos = System.nanoTime();
463                     n = implAccept(fd, newfd, saa);
464                     while (n == IOStatus.UNAVAILABLE && isOpen()) {
465                         long remainingNanos = nanos - (System.nanoTime() - startNanos);
466                         if (remainingNanos <= 0) {
467                             throw new SocketTimeoutException("Accept timed out");
468                         }
469                         park(Net.POLLIN, remainingNanos);
470                         n = implAccept(fd, newfd, saa);
471                     }
472                 } finally {
473                     // restore socket to blocking mode (if channel is open)
474                     tryLockedConfigureBlocking(true);
475                 }
476             } finally {
477                 end(true, n > 0);
478             }
479         } finally {
480             acceptLock.unlock();
481         }
482 
483         assert n > 0;
484         return finishAccept(newfd, saa[0]);
485     }
486 
487     private SocketChannel finishAccept(FileDescriptor newfd, SocketAddress sa)
488         throws IOException
489     {
490         try {
491             // newly accepted socket is initially in blocking mode
492             IOUtil.configureBlocking(newfd, true);
493 
494             // check permitted to accept connections from the remote address
495             if (isNetSocket()) {
496                 @SuppressWarnings("removal")
497                 SecurityManager sm = System.getSecurityManager();
498                 if (sm != null) {
499                     InetSocketAddress isa = (InetSocketAddress) sa;
500                     sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
501                 }
502             }
503             return new SocketChannelImpl(provider(), family, newfd, sa);
504         } catch (Exception e) {
505             nd.close(newfd);
506             throw e;
507         }
508     }
509 
510     @Override
511     protected void implConfigureBlocking(boolean block) throws IOException {
512         acceptLock.lock();
513         try {
514             lockedConfigureBlocking(block);
515         } finally {
516             acceptLock.unlock();
517         }
518     }
519 
520     /**
521      * Adjusts the blocking mode.
522      */
523     private void lockedConfigureBlocking(boolean block) throws IOException {
524         assert acceptLock.isHeldByCurrentThread();
525         synchronized (stateLock) {
526             ensureOpen();
527             // do nothing if virtual thread has forced the socket to be non-blocking
528             if (!nonBlocking) {
529                 IOUtil.configureBlocking(fd, block);
530             }
531         }
532     }
533 
534     /**
535      * Attempts to adjusts the blocking mode if the channel is open.
536      * @return {@code true} if the blocking mode was adjusted
537      */
538     private boolean tryLockedConfigureBlocking(boolean block) throws IOException {
539         assert acceptLock.isHeldByCurrentThread();
540         synchronized (stateLock) {
541             // do nothing if virtual thread has forced the socket to be non-blocking
542             if (!nonBlocking && isOpen()) {
543                 IOUtil.configureBlocking(fd, block);
544                 return true;
545             } else {
546                 return false;
547             }
548         }
549     }
550 
551     /**
552      * Ensures that the socket is configured non-blocking when on a virtual
553      * thread.
554      */
555     private void lockedConfigureNonBlockingIfNeeded() throws IOException {
556         assert acceptLock.isHeldByCurrentThread();
557         if (!nonBlocking && (Thread.currentThread().isVirtual())) {
558             synchronized (stateLock) {
559                 ensureOpen();
560                 IOUtil.configureBlocking(fd, false);
561                 nonBlocking = true;
562             }
563         }
564     }
565 
566     /**
567      * Closes the socket if there are no accept in progress and the channel is
568      * not registered with a Selector.
569      */
570     private boolean tryClose() throws IOException {
571         assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
572         if ((thread == 0) && !isRegistered()) {
573             state = ST_CLOSED;
574             nd.close(fd);
575             return true;
576         } else {
577             return false;
578         }
579     }
580 
581     /**
582      * Invokes tryClose to attempt to close the socket.
583      *
584      * This method is used for deferred closing by I/O and Selector operations.
585      */
586     private void tryFinishClose() {
587         try {
588             tryClose();
589         } catch (IOException ignore) { }
590     }
591 
592     /**
593      * Closes this channel when configured in blocking mode.
594      *
595      * If there is an accept in progress then the socket is pre-closed and the
596      * accept thread is signalled, in which case the final close is deferred
597      * until the accept aborts.
598      */
599     private void implCloseBlockingMode() throws IOException {
600         synchronized (stateLock) {
601             assert state < ST_CLOSING;
602             state = ST_CLOSING;
603             if (!tryClose()) {
604                 long th = thread;
605                 if (th != 0) {
606                     if (NativeThread.isVirtualThread(th)) {
607                         Poller.stopPoll(fdVal);
608                     } else {
609                         nd.preClose(fd);
610                         NativeThread.signal(th);
611                     }
612                 }
613             }
614         }
615     }
616 
617     /**
618      * Closes this channel when configured in non-blocking mode.
619      *
620      * If the channel is registered with a Selector then the close is deferred
621      * until the channel is flushed from all Selectors.
622      */
623     private void implCloseNonBlockingMode() throws IOException {
624         synchronized (stateLock) {
625             assert state < ST_CLOSING;
626             state = ST_CLOSING;
627         }
628         // wait for any accept to complete before trying to close
629         acceptLock.lock();
630         acceptLock.unlock();
631         synchronized (stateLock) {
632             if (state == ST_CLOSING) {
633                 tryClose();
634             }
635         }
636     }
637 
638     /**
639      * Invoked by implCloseChannel to close the channel.
640      */
641     @Override
642     protected void implCloseSelectableChannel() throws IOException {
643         assert !isOpen();
644         if (isBlocking()) {
645             implCloseBlockingMode();
646         } else {
647             implCloseNonBlockingMode();
648         }
649     }
650 
651     @Override
652     public void kill() {
653         synchronized (stateLock) {
654             if (state == ST_CLOSING) {
655                 tryFinishClose();
656             }
657         }
658     }
659 
660     /**
661      * Returns true if channel's socket is bound
662      */
663     boolean isBound() {
664         synchronized (stateLock) {
665             return localAddress != null;
666         }
667     }
668 
669     /**
670      * Returns the local address, or null if not bound
671      */
672     SocketAddress localAddress() {
673         synchronized (stateLock) {
674             return localAddress;
675         }
676     }
677 
678     /**
679      * Translates native poll revent set into a ready operation set
680      */
681     public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
682         int intOps = ski.nioInterestOps();
683         int oldOps = ski.nioReadyOps();
684         int newOps = initialOps;
685 
686         if ((ops & Net.POLLNVAL) != 0) {
687             // This should only happen if this channel is pre-closed while a
688             // selection operation is in progress
689             // ## Throw an error if this channel has not been pre-closed
690             return false;
691         }
692 
693         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
694             newOps = intOps;
695             ski.nioReadyOps(newOps);
696             return (newOps & ~oldOps) != 0;
697         }
698 
699         if (((ops & Net.POLLIN) != 0) &&
700             ((intOps & SelectionKey.OP_ACCEPT) != 0))
701                 newOps |= SelectionKey.OP_ACCEPT;
702 
703         ski.nioReadyOps(newOps);
704         return (newOps & ~oldOps) != 0;
705     }
706 
707     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
708         return translateReadyOps(ops, ski.nioReadyOps(), ski);
709     }
710 
711     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
712         return translateReadyOps(ops, 0, ski);
713     }
714 
715     /**
716      * Translates an interest operation set into a native poll event set
717      */
718     public int translateInterestOps(int ops) {
719         int newOps = 0;
720         if ((ops & SelectionKey.OP_ACCEPT) != 0)
721             newOps |= Net.POLLIN;
722         return newOps;
723     }
724 
725     public FileDescriptor getFD() {
726         return fd;
727     }
728 
729     public int getFDVal() {
730         return fdVal;
731     }
732 
733     public String toString() {
734         StringBuilder sb = new StringBuilder();
735         sb.append(this.getClass().getName());
736         sb.append('[');
737         if (!isOpen()) {
738             sb.append("closed");
739         } else {
740             synchronized (stateLock) {
741                 SocketAddress addr = localAddress;
742                 if (addr == null) {
743                     sb.append("unbound");
744                 } else if (isUnixSocket()) {
745                     sb.append(UnixDomainSockets.getRevealedLocalAddressAsString(addr));
746                 } else {
747                     sb.append(Net.getRevealedLocalAddressAsString(addr));
748                 }
749             }
750         }
751         sb.append(']');
752         return sb.toString();
753     }
754 }