src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
branchunixdomainchannels
changeset 58801 119ac9128c1b
parent 55081 dd321e3596c0
child 58847 692de65ab293
equal deleted inserted replaced
58799:eb491334113f 58801:119ac9128c1b
    53 
    53 
    54 /**
    54 /**
    55  * An implementation of ServerSocketChannels
    55  * An implementation of ServerSocketChannels
    56  */
    56  */
    57 
    57 
    58 class ServerSocketChannelImpl
    58 public abstract class ServerSocketChannelImpl
    59     extends ServerSocketChannel
    59     extends ServerSocketChannel
    60     implements SelChImpl
    60     implements SelChImpl
    61 {
    61 {
    62     // Used to make native close and configure calls
    62     // Used to make native close and configure calls
    63     private static final NativeDispatcher nd = new SocketDispatcher();
    63     static final NativeDispatcher nd = new SocketDispatcher();
    64 
    64 
    65     // Our file descriptor
    65     // Our file descriptor
    66     private final FileDescriptor fd;
    66     final FileDescriptor fd;
    67     private final int fdVal;
    67     final int fdVal;
    68 
    68 
    69     // Lock held by thread currently blocked on this channel
    69     // Lock held by thread currently blocked on this channel
    70     private final ReentrantLock acceptLock = new ReentrantLock();
    70     final ReentrantLock acceptLock = new ReentrantLock();
    71 
    71 
    72     // Lock held by any thread that modifies the state fields declared below
    72     // Lock held by any thread that modifies the state fields declared below
    73     // DO NOT invoke a blocking I/O operation while holding this lock!
    73     // DO NOT invoke a blocking I/O operation while holding this lock!
    74     private final Object stateLock = new Object();
    74     final Object stateLock = new Object();
    75 
    75 
    76     // -- The following fields are protected by stateLock
    76     // -- The following fields are protected by stateLock
    77 
    77 
    78     // Channel state, increases monotonically
    78     // Channel state, increases monotonically
    79     private static final int ST_INUSE = 0;
    79     static final int ST_INUSE = 0;
    80     private static final int ST_CLOSING = 1;
    80     static final int ST_CLOSING = 1;
    81     private static final int ST_CLOSED = 2;
    81     static final int ST_CLOSED = 2;
    82     private int state;
    82     int state;
    83 
    83 
    84     // ID of native thread currently blocked in this channel, for signalling
    84     // ID of native thread currently blocked in this channel, for signalling
    85     private long thread;
    85     long thread;
    86 
    86 
    87     // Binding
    87     // Binding
    88     private InetSocketAddress localAddress; // null => unbound
    88     SocketAddress localAddress; // null => unbound
    89 
       
    90     // set true when exclusive binding is on and SO_REUSEADDR is emulated
       
    91     private boolean isReuseAddress;
       
    92 
       
    93     // Our socket adaptor, if any
       
    94     private ServerSocket socket;
       
    95 
    89 
    96     // -- End of fields protected by stateLock
    90     // -- End of fields protected by stateLock
    97 
    91 
    98 
    92     ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd)
    99     ServerSocketChannelImpl(SelectorProvider sp) {
       
   100         super(sp);
       
   101         this.fd = Net.serverSocket(true);
       
   102         this.fdVal = IOUtil.fdVal(fd);
       
   103     }
       
   104 
       
   105     ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
       
   106         throws IOException
    93         throws IOException
   107     {
    94     {
   108         super(sp);
    95         super(sp);
   109         this.fd =  fd;
    96         this.fd =  fd;
   110         this.fdVal = IOUtil.fdVal(fd);
    97         this.fdVal = IOUtil.fdVal(fd);
   111         if (bound) {
       
   112             synchronized (stateLock) {
       
   113                 localAddress = Net.localAddress(fd);
       
   114             }
       
   115         }
       
   116     }
    98     }
   117 
    99 
   118     // @throws ClosedChannelException if channel is closed
   100     // @throws ClosedChannelException if channel is closed
   119     private void ensureOpen() throws ClosedChannelException {
   101     void ensureOpen() throws ClosedChannelException {
   120         if (!isOpen())
   102         if (!isOpen())
   121             throw new ClosedChannelException();
   103             throw new ClosedChannelException();
   122     }
   104     }
   123 
   105 
   124     @Override
   106     abstract SocketAddress getRevealedLocalAddress(SocketAddress addr);
   125     public ServerSocket socket() {
   107 
   126         synchronized (stateLock) {
   108     abstract String getRevealedLocalAddressAsString(SocketAddress addr);
   127             if (socket == null)
       
   128                 socket = ServerSocketAdaptor.create(this);
       
   129             return socket;
       
   130         }
       
   131     }
       
   132 
   109 
   133     @Override
   110     @Override
   134     public SocketAddress getLocalAddress() throws IOException {
   111     public SocketAddress getLocalAddress() throws IOException {
   135         synchronized (stateLock) {
   112         synchronized (stateLock) {
   136             ensureOpen();
   113             ensureOpen();
   137             return (localAddress == null)
   114             return (localAddress == null)
   138                     ? null
   115                     ? null
   139                     : Net.getRevealedLocalAddress(localAddress);
   116                     : getRevealedLocalAddress(localAddress);
   140         }
   117         }
   141     }
   118     }
   142 
   119 
   143     @Override
       
   144     public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
       
   145         throws IOException
       
   146     {
       
   147         Objects.requireNonNull(name);
       
   148         if (!supportedOptions().contains(name))
       
   149             throw new UnsupportedOperationException("'" + name + "' not supported");
       
   150         if (!name.type().isInstance(value))
       
   151             throw new IllegalArgumentException("Invalid value '" + value + "'");
       
   152 
       
   153         synchronized (stateLock) {
       
   154             ensureOpen();
       
   155 
       
   156             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
       
   157                 // SO_REUSEADDR emulated when using exclusive bind
       
   158                 isReuseAddress = (Boolean)value;
       
   159             } else {
       
   160                 // no options that require special handling
       
   161                 Net.setSocketOption(fd, Net.UNSPEC, name, value);
       
   162             }
       
   163             return this;
       
   164         }
       
   165     }
       
   166 
       
   167     @Override
       
   168     @SuppressWarnings("unchecked")
       
   169     public <T> T getOption(SocketOption<T> name)
       
   170         throws IOException
       
   171     {
       
   172         Objects.requireNonNull(name);
       
   173         if (!supportedOptions().contains(name))
       
   174             throw new UnsupportedOperationException("'" + name + "' not supported");
       
   175 
       
   176         synchronized (stateLock) {
       
   177             ensureOpen();
       
   178             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
       
   179                 // SO_REUSEADDR emulated when using exclusive bind
       
   180                 return (T)Boolean.valueOf(isReuseAddress);
       
   181             }
       
   182             // no options that require special handling
       
   183             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
       
   184         }
       
   185     }
       
   186 
       
   187     private static class DefaultOptionsHolder {
       
   188         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
       
   189 
       
   190         private static Set<SocketOption<?>> defaultOptions() {
       
   191             HashSet<SocketOption<?>> set = new HashSet<>();
       
   192             set.add(StandardSocketOptions.SO_RCVBUF);
       
   193             set.add(StandardSocketOptions.SO_REUSEADDR);
       
   194             if (Net.isReusePortAvailable()) {
       
   195                 set.add(StandardSocketOptions.SO_REUSEPORT);
       
   196             }
       
   197             set.addAll(ExtendedSocketOptions.serverSocketOptions());
       
   198             return Collections.unmodifiableSet(set);
       
   199         }
       
   200     }
       
   201 
       
   202     @Override
       
   203     public final Set<SocketOption<?>> supportedOptions() {
       
   204         return DefaultOptionsHolder.defaultOptions;
       
   205     }
       
   206 
       
   207     @Override
       
   208     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
       
   209         synchronized (stateLock) {
       
   210             ensureOpen();
       
   211             if (localAddress != null)
       
   212                 throw new AlreadyBoundException();
       
   213             InetSocketAddress isa = (local == null)
       
   214                                     ? new InetSocketAddress(0)
       
   215                                     : Net.checkAddress(local);
       
   216             SecurityManager sm = System.getSecurityManager();
       
   217             if (sm != null)
       
   218                 sm.checkListen(isa.getPort());
       
   219             NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
       
   220             Net.bind(fd, isa.getAddress(), isa.getPort());
       
   221             Net.listen(fd, backlog < 1 ? 50 : backlog);
       
   222             localAddress = Net.localAddress(fd);
       
   223         }
       
   224         return this;
       
   225     }
       
   226 
   120 
   227     /**
   121     /**
   228      * Marks the beginning of an I/O operation that might block.
   122      * Marks the beginning of an I/O operation that might block.
   229      *
   123      *
   230      * @throws ClosedChannelException if the channel is closed
   124      * @throws ClosedChannelException if the channel is closed
   260             }
   154             }
   261             end(completed);
   155             end(completed);
   262         }
   156         }
   263     }
   157     }
   264 
   158 
       
   159     abstract int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] sa)
       
   160         throws IOException;
       
   161 
   265     @Override
   162     @Override
   266     public SocketChannel accept() throws IOException {
   163     public SocketChannel accept() throws IOException {
   267         int n = 0;
   164         int n = 0;
   268         FileDescriptor newfd = new FileDescriptor();
   165         FileDescriptor newfd = new FileDescriptor();
   269         InetSocketAddress[] isaa = new InetSocketAddress[1];
   166         SocketAddress[] isaa = new SocketAddress[1];
   270 
   167 
   271         acceptLock.lock();
   168         acceptLock.lock();
   272         try {
   169         try {
   273             boolean blocking = isBlocking();
   170             boolean blocking = isBlocking();
   274             try {
   171             try {
   275                 begin(blocking);
   172                 begin(blocking);
   276                 n = Net.accept(this.fd, newfd, isaa);
   173                 n = implAccept(this.fd, newfd, isaa);
   277                 if (blocking) {
   174                 if (blocking) {
   278                     while (IOStatus.okayToRetry(n) && isOpen()) {
   175                     while (IOStatus.okayToRetry(n) && isOpen()) {
   279                         park(Net.POLLIN);
   176                         park(Net.POLLIN);
   280                         n = Net.accept(this.fd, newfd, isaa);
   177                         n = implAccept(this.fd, newfd, isaa);
   281                     }
   178                     }
   282                 }
   179                 }
   283             } finally {
   180             } finally {
   284                 end(blocking, n > 0);
   181                 end(blocking, n > 0);
   285                 assert IOStatus.check(n);
   182                 assert IOStatus.check(n);
   306      * @throws SocketTimeoutException if the timeout expires
   203      * @throws SocketTimeoutException if the timeout expires
   307      */
   204      */
   308     SocketChannel blockingAccept(long nanos) throws IOException {
   205     SocketChannel blockingAccept(long nanos) throws IOException {
   309         int n = 0;
   206         int n = 0;
   310         FileDescriptor newfd = new FileDescriptor();
   207         FileDescriptor newfd = new FileDescriptor();
   311         InetSocketAddress[] isaa = new InetSocketAddress[1];
   208         SocketAddress[] isaa = new SocketAddress[1];
   312 
   209 
   313         acceptLock.lock();
   210         acceptLock.lock();
   314         try {
   211         try {
   315             // check that channel is configured blocking
   212             // check that channel is configured blocking
   316             if (!isBlocking())
   213             if (!isBlocking())
   320                 begin(true);
   217                 begin(true);
   321                 // change socket to non-blocking
   218                 // change socket to non-blocking
   322                 lockedConfigureBlocking(false);
   219                 lockedConfigureBlocking(false);
   323                 try {
   220                 try {
   324                     long startNanos = System.nanoTime();
   221                     long startNanos = System.nanoTime();
   325                     n = Net.accept(fd, newfd, isaa);
   222                     n = implAccept(fd, newfd, isaa);
   326                     while (n == IOStatus.UNAVAILABLE && isOpen()) {
   223                     while (n == IOStatus.UNAVAILABLE && isOpen()) {
   327                         long remainingNanos = nanos - (System.nanoTime() - startNanos);
   224                         long remainingNanos = nanos - (System.nanoTime() - startNanos);
   328                         if (remainingNanos <= 0) {
   225                         if (remainingNanos <= 0) {
   329                             throw new SocketTimeoutException("Accept timed out");
   226                             throw new SocketTimeoutException("Accept timed out");
   330                         }
   227                         }
   331                         park(Net.POLLIN, remainingNanos);
   228                         park(Net.POLLIN, remainingNanos);
   332                         n = Net.accept(fd, newfd, isaa);
   229                         n = implAccept(fd, newfd, isaa);
   333                     }
   230                     }
   334                 } finally {
   231                 } finally {
   335                     // restore socket to blocking mode
   232                     // restore socket to blocking mode
   336                     lockedConfigureBlocking(true);
   233                     lockedConfigureBlocking(true);
   337                 }
   234                 }
   344 
   241 
   345         assert n > 0;
   242         assert n > 0;
   346         return finishAccept(newfd, isaa[0]);
   243         return finishAccept(newfd, isaa[0]);
   347     }
   244     }
   348 
   245 
   349     private SocketChannel finishAccept(FileDescriptor newfd, InetSocketAddress isa)
   246     abstract SocketChannel finishAccept(FileDescriptor newfd, SocketAddress isa)
   350         throws IOException
   247         throws IOException;
   351     {
       
   352         try {
       
   353             // newly accepted socket is initially in blocking mode
       
   354             IOUtil.configureBlocking(newfd, true);
       
   355 
       
   356             // check permitted to accept connections from the remote address
       
   357             SecurityManager sm = System.getSecurityManager();
       
   358             if (sm != null) {
       
   359                 sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
       
   360             }
       
   361             return new SocketChannelImpl(provider(), newfd, isa);
       
   362         } catch (Exception e) {
       
   363             nd.close(newfd);
       
   364             throw e;
       
   365         }
       
   366     }
       
   367 
   248 
   368     @Override
   249     @Override
   369     protected void implConfigureBlocking(boolean block) throws IOException {
   250     protected void implConfigureBlocking(boolean block) throws IOException {
   370         acceptLock.lock();
   251         acceptLock.lock();
   371         try {
   252         try {
   486     }
   367     }
   487 
   368 
   488     /**
   369     /**
   489      * Returns the local address, or null if not bound
   370      * Returns the local address, or null if not bound
   490      */
   371      */
   491     InetSocketAddress localAddress() {
   372     SocketAddress localAddress() {
   492         synchronized (stateLock) {
   373         synchronized (stateLock) {
   493             return localAddress;
   374             return localAddress;
   494         }
   375         }
   495     }
   376     }
   496 
   377 
   555         sb.append('[');
   436         sb.append('[');
   556         if (!isOpen()) {
   437         if (!isOpen()) {
   557             sb.append("closed");
   438             sb.append("closed");
   558         } else {
   439         } else {
   559             synchronized (stateLock) {
   440             synchronized (stateLock) {
   560                 InetSocketAddress addr = localAddress;
   441                 SocketAddress addr = localAddress;
   561                 if (addr == null) {
   442                 if (addr == null) {
   562                     sb.append("unbound");
   443                     sb.append("unbound");
   563                 } else {
   444                 } else {
   564                     sb.append(Net.getRevealedLocalAddressAsString(addr));
   445                     sb.append(getRevealedLocalAddressAsString(addr));
   565                 }
   446                 }
   566             }
   447             }
   567         }
   448         }
   568         sb.append(']');
   449         sb.append(']');
   569         return sb.toString();
   450         return sb.toString();