jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
changeset 2 90ce3da70b43
child 1152 29d6145d1097
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2000-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.nio.ch;
       
    27 
       
    28 import java.io.FileDescriptor;
       
    29 import java.io.IOException;
       
    30 import java.lang.reflect.*;
       
    31 import java.net.*;
       
    32 import java.nio.channels.*;
       
    33 import java.nio.channels.spi.*;
       
    34 import java.security.AccessController;
       
    35 import java.security.PrivilegedAction;
       
    36 import java.util.HashSet;
       
    37 import java.util.Iterator;
       
    38 
       
    39 
       
    40 /**
       
    41  * An implementation of ServerSocketChannels
       
    42  */
       
    43 
       
    44 class ServerSocketChannelImpl
       
    45     extends ServerSocketChannel
       
    46     implements SelChImpl
       
    47 {
       
    48 
       
    49     // Used to make native close and configure calls
       
    50     private static NativeDispatcher nd;
       
    51 
       
    52     // Our file descriptor
       
    53     private final FileDescriptor fd;
       
    54 
       
    55     // fd value needed for dev/poll. This value will remain valid
       
    56     // even after the value in the file descriptor object has been set to -1
       
    57     private int fdVal;
       
    58 
       
    59     // ID of native thread currently blocked in this channel, for signalling
       
    60     private volatile long thread = 0;
       
    61 
       
    62     // Lock held by thread currently blocked in this channel
       
    63     private final Object lock = new Object();
       
    64 
       
    65     // Lock held by any thread that modifies the state fields declared below
       
    66     // DO NOT invoke a blocking I/O operation while holding this lock!
       
    67     private final Object stateLock = new Object();
       
    68 
       
    69     // -- The following fields are protected by stateLock
       
    70 
       
    71     // Channel state, increases monotonically
       
    72     private static final int ST_UNINITIALIZED = -1;
       
    73     private static final int ST_INUSE = 0;
       
    74     private static final int ST_KILLED = 1;
       
    75     private int state = ST_UNINITIALIZED;
       
    76 
       
    77     // Binding
       
    78     private SocketAddress localAddress = null; // null => unbound
       
    79 
       
    80     // Options, created on demand
       
    81     private SocketOpts.IP.TCP options = null;
       
    82 
       
    83     // Our socket adaptor, if any
       
    84     ServerSocket socket;
       
    85 
       
    86     // -- End of fields protected by stateLock
       
    87 
       
    88 
       
    89     public ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
       
    90         super(sp);
       
    91         this.fd =  Net.serverSocket(true);
       
    92         this.fdVal = IOUtil.fdVal(fd);
       
    93         this.state = ST_INUSE;
       
    94     }
       
    95 
       
    96     public ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd)
       
    97         throws IOException
       
    98     {
       
    99         super(sp);
       
   100         this.fd =  fd;
       
   101         this.fdVal = IOUtil.fdVal(fd);
       
   102         this.state = ST_INUSE;
       
   103         localAddress = Net.localAddress(fd);
       
   104     }
       
   105 
       
   106 
       
   107     public ServerSocket socket() {
       
   108         synchronized (stateLock) {
       
   109             if (socket == null)
       
   110                 socket = ServerSocketAdaptor.create(this);
       
   111             return socket;
       
   112         }
       
   113     }
       
   114 
       
   115     public boolean isBound() {
       
   116         synchronized (stateLock) {
       
   117             return localAddress != null;
       
   118         }
       
   119     }
       
   120 
       
   121     public SocketAddress localAddress() {
       
   122         synchronized (stateLock) {
       
   123             return localAddress;
       
   124         }
       
   125     }
       
   126 
       
   127     public void bind(SocketAddress local, int backlog) throws IOException {
       
   128         synchronized (lock) {
       
   129             if (!isOpen())
       
   130                 throw new ClosedChannelException();
       
   131             if (isBound())
       
   132                 throw new AlreadyBoundException();
       
   133             InetSocketAddress isa = Net.checkAddress(local);
       
   134             SecurityManager sm = System.getSecurityManager();
       
   135             if (sm != null)
       
   136                 sm.checkListen(isa.getPort());
       
   137             Net.bind(fd, isa.getAddress(), isa.getPort());
       
   138             listen(fd, backlog < 1 ? 50 : backlog);
       
   139             synchronized (stateLock) {
       
   140                 localAddress = Net.localAddress(fd);
       
   141             }
       
   142         }
       
   143     }
       
   144 
       
   145     public SocketChannel accept() throws IOException {
       
   146         synchronized (lock) {
       
   147             if (!isOpen())
       
   148                 throw new ClosedChannelException();
       
   149             if (!isBound())
       
   150                 throw new NotYetBoundException();
       
   151             SocketChannel sc = null;
       
   152 
       
   153             int n = 0;
       
   154             FileDescriptor newfd = new FileDescriptor();
       
   155             InetSocketAddress[] isaa = new InetSocketAddress[1];
       
   156 
       
   157             try {
       
   158                 begin();
       
   159                 if (!isOpen())
       
   160                     return null;
       
   161                 thread = NativeThread.current();
       
   162                 for (;;) {
       
   163                     n = accept0(this.fd, newfd, isaa);
       
   164                     if ((n == IOStatus.INTERRUPTED) && isOpen())
       
   165                         continue;
       
   166                     break;
       
   167                 }
       
   168             } finally {
       
   169                 thread = 0;
       
   170                 end(n > 0);
       
   171                 assert IOStatus.check(n);
       
   172             }
       
   173 
       
   174             if (n < 1)
       
   175                 return null;
       
   176 
       
   177             IOUtil.configureBlocking(newfd, true);
       
   178             InetSocketAddress isa = isaa[0];
       
   179             sc = new SocketChannelImpl(provider(), newfd, isa);
       
   180             SecurityManager sm = System.getSecurityManager();
       
   181             if (sm != null) {
       
   182                 try {
       
   183                     sm.checkAccept(isa.getAddress().getHostAddress(),
       
   184                                    isa.getPort());
       
   185                 } catch (SecurityException x) {
       
   186                     sc.close();
       
   187                     throw x;
       
   188                 }
       
   189             }
       
   190             return sc;
       
   191 
       
   192         }
       
   193     }
       
   194 
       
   195     protected void implConfigureBlocking(boolean block) throws IOException {
       
   196         IOUtil.configureBlocking(fd, block);
       
   197     }
       
   198 
       
   199     public SocketOpts options() {
       
   200         synchronized (stateLock) {
       
   201             if (options == null) {
       
   202                 SocketOptsImpl.Dispatcher d
       
   203                     = new SocketOptsImpl.Dispatcher() {
       
   204                             int getInt(int opt) throws IOException {
       
   205                                 return Net.getIntOption(fd, opt);
       
   206                             }
       
   207                             void setInt(int opt, int arg) throws IOException {
       
   208                                 Net.setIntOption(fd, opt, arg);
       
   209                             }
       
   210                         };
       
   211                 options = new SocketOptsImpl.IP.TCP(d);
       
   212             }
       
   213             return options;
       
   214         }
       
   215     }
       
   216 
       
   217     protected void implCloseSelectableChannel() throws IOException {
       
   218         synchronized (stateLock) {
       
   219             nd.preClose(fd);
       
   220             long th = thread;
       
   221             if (th != 0)
       
   222                 NativeThread.signal(th);
       
   223             if (!isRegistered())
       
   224                 kill();
       
   225         }
       
   226     }
       
   227 
       
   228     public void kill() throws IOException {
       
   229         synchronized (stateLock) {
       
   230             if (state == ST_KILLED)
       
   231                 return;
       
   232             if (state == ST_UNINITIALIZED) {
       
   233                 state = ST_KILLED;
       
   234                 return;
       
   235             }
       
   236             assert !isOpen() && !isRegistered();
       
   237             nd.close(fd);
       
   238             state = ST_KILLED;
       
   239         }
       
   240     }
       
   241 
       
   242     /**
       
   243      * Translates native poll revent set into a ready operation set
       
   244      */
       
   245     public boolean translateReadyOps(int ops, int initialOps,
       
   246                                      SelectionKeyImpl sk) {
       
   247         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
       
   248         int oldOps = sk.nioReadyOps();
       
   249         int newOps = initialOps;
       
   250 
       
   251         if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
       
   252             // This should only happen if this channel is pre-closed while a
       
   253             // selection operation is in progress
       
   254             // ## Throw an error if this channel has not been pre-closed
       
   255             return false;
       
   256         }
       
   257 
       
   258         if ((ops & (PollArrayWrapper.POLLERR
       
   259                     | PollArrayWrapper.POLLHUP)) != 0) {
       
   260             newOps = intOps;
       
   261             sk.nioReadyOps(newOps);
       
   262             return (newOps & ~oldOps) != 0;
       
   263         }
       
   264 
       
   265         if (((ops & PollArrayWrapper.POLLIN) != 0) &&
       
   266             ((intOps & SelectionKey.OP_ACCEPT) != 0))
       
   267                 newOps |= SelectionKey.OP_ACCEPT;
       
   268 
       
   269         sk.nioReadyOps(newOps);
       
   270         return (newOps & ~oldOps) != 0;
       
   271     }
       
   272 
       
   273     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
       
   274         return translateReadyOps(ops, sk.nioReadyOps(), sk);
       
   275     }
       
   276 
       
   277     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
       
   278         return translateReadyOps(ops, 0, sk);
       
   279     }
       
   280 
       
   281     /**
       
   282      * Translates an interest operation set into a native poll event set
       
   283      */
       
   284     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
       
   285         int newOps = 0;
       
   286 
       
   287         // Translate ops
       
   288         if ((ops & SelectionKey.OP_ACCEPT) != 0)
       
   289             newOps |= PollArrayWrapper.POLLIN;
       
   290         // Place ops into pollfd array
       
   291         sk.selector.putEventOps(sk, newOps);
       
   292     }
       
   293 
       
   294     public FileDescriptor getFD() {
       
   295         return fd;
       
   296     }
       
   297 
       
   298     public int getFDVal() {
       
   299         return fdVal;
       
   300     }
       
   301 
       
   302     public String toString() {
       
   303         StringBuffer sb = new StringBuffer();
       
   304         sb.append(this.getClass().getName());
       
   305         sb.append('[');
       
   306         if (!isOpen())
       
   307             sb.append("closed");
       
   308         else {
       
   309             synchronized (stateLock) {
       
   310                 if (localAddress() == null) {
       
   311                     sb.append("unbound");
       
   312                 } else {
       
   313                     sb.append(localAddress().toString());
       
   314                 }
       
   315             }
       
   316         }
       
   317         sb.append(']');
       
   318         return sb.toString();
       
   319     }
       
   320 
       
   321     // -- Native methods --
       
   322 
       
   323     private static native void listen(FileDescriptor fd, int backlog)
       
   324         throws IOException;
       
   325 
       
   326     // Accepts a new connection, setting the given file descriptor to refer to
       
   327     // the new socket and setting isaa[0] to the socket's remote address.
       
   328     // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
       
   329     // connections are pending) or IOStatus.INTERRUPTED.
       
   330     //
       
   331     private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
       
   332                                InetSocketAddress[] isaa)
       
   333         throws IOException;
       
   334 
       
   335     private static native void initIDs();
       
   336 
       
   337     static {
       
   338         Util.load();
       
   339         initIDs();
       
   340         nd = new SocketDispatcher();
       
   341     }
       
   342 
       
   343 }