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 }