Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package sun.nio.ch;
     28 
     29 import java.io.FileDescriptor;
     30 import java.io.IOException;
     31 import java.net.*;
     32 import java.nio.ByteBuffer;
     33 import java.nio.channels.*;
     34 import java.nio.channels.spi.*;
     35 import java.util.*;
     36 
     37 import dalvik.system.BlockGuard;
     38 import sun.net.ResourceManager;
     39 
     40 
     41 /**
     42  * An implementation of DatagramChannels.
     43  */
     44 
     45 class DatagramChannelImpl
     46     extends DatagramChannel
     47     implements SelChImpl
     48 {
     49 
     50     // Used to make native read and write calls
     51     private static NativeDispatcher nd = new DatagramDispatcher();
     52 
     53     // Our file descriptor
     54     // Android-changed: Make the fd package visible so that we can expose it through DatagramSocketAdaptor.
     55     final FileDescriptor fd;
     56 
     57     // fd value needed for dev/poll. This value will remain valid
     58     // even after the value in the file descriptor object has been set to -1
     59     private final int fdVal;
     60 
     61     // The protocol family of the socket
     62     private final ProtocolFamily family;
     63 
     64     // IDs of native threads doing reads and writes, for signalling
     65     private volatile long readerThread = 0;
     66     private volatile long writerThread = 0;
     67 
     68     // Cached InetAddress and port for unconnected DatagramChannels
     69     // used by receive0
     70     private InetAddress cachedSenderInetAddress;
     71     private int cachedSenderPort;
     72 
     73     // Lock held by current reading or connecting thread
     74     private final Object readLock = new Object();
     75 
     76     // Lock held by current writing or connecting thread
     77     private final Object writeLock = new Object();
     78 
     79     // Lock held by any thread that modifies the state fields declared below
     80     // DO NOT invoke a blocking I/O operation while holding this lock!
     81     private final Object stateLock = new Object();
     82 
     83     // -- The following fields are protected by stateLock
     84 
     85     // State (does not necessarily increase monotonically)
     86     private static final int ST_UNINITIALIZED = -1;
     87     private static final int ST_UNCONNECTED = 0;
     88     private static final int ST_CONNECTED = 1;
     89     private static final int ST_KILLED = 2;
     90     private int state = ST_UNINITIALIZED;
     91 
     92     // Binding
     93     private InetSocketAddress localAddress;
     94     private InetSocketAddress remoteAddress;
     95 
     96     // Our socket adaptor, if any
     97     private DatagramSocket socket;
     98 
     99     // set true when socket is bound and SO_REUSEADDRESS is emulated
    100     private boolean reuseAddressEmulated;
    101 
    102     // set true/false when socket is already bound and SO_REUSEADDR is emulated
    103     private boolean isReuseAddress;
    104 
    105     // -- End of fields protected by stateLock
    106 
    107 
    108     public DatagramChannelImpl(SelectorProvider sp)
    109         throws IOException
    110     {
    111         super(sp);
    112         ResourceManager.beforeUdpCreate();
    113         try {
    114             this.family = Net.isIPv6Available() ?
    115                 StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
    116             this.fd = Net.socket(family, false);
    117             this.fdVal = IOUtil.fdVal(fd);
    118             this.state = ST_UNCONNECTED;
    119         } catch (IOException ioe) {
    120             ResourceManager.afterUdpClose();
    121             throw ioe;
    122         }
    123     }
    124 
    125     public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family)
    126         throws IOException
    127     {
    128         super(sp);
    129         if ((family != StandardProtocolFamily.INET) &&
    130             (family != StandardProtocolFamily.INET6))
    131         {
    132             if (family == null)
    133                 throw new NullPointerException("'family' is null");
    134             else
    135                 throw new UnsupportedOperationException("Protocol family not supported");
    136         }
    137         if (family == StandardProtocolFamily.INET6) {
    138             if (!Net.isIPv6Available()) {
    139                 throw new UnsupportedOperationException("IPv6 not available");
    140             }
    141         }
    142         this.family = family;
    143         this.fd = Net.socket(family, false);
    144         this.fdVal = IOUtil.fdVal(fd);
    145         this.state = ST_UNCONNECTED;
    146     }
    147 
    148     public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
    149         throws IOException
    150     {
    151         super(sp);
    152         this.family = Net.isIPv6Available() ?
    153             StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
    154         this.fd = fd;
    155         this.fdVal = IOUtil.fdVal(fd);
    156         this.state = ST_UNCONNECTED;
    157         this.localAddress = Net.localAddress(fd);
    158     }
    159 
    160     public DatagramSocket socket() {
    161         synchronized (stateLock) {
    162             if (socket == null)
    163                 socket = DatagramSocketAdaptor.create(this);
    164             return socket;
    165         }
    166     }
    167 
    168     public SocketAddress getLocalAddress() throws IOException {
    169         synchronized (stateLock) {
    170             if (!isOpen())
    171                 throw new ClosedChannelException();
    172             return Net.getRevealedLocalAddress(localAddress);
    173         }
    174     }
    175 
    176     @Override
    177     public SocketAddress getRemoteAddress() throws IOException {
    178         synchronized (stateLock) {
    179             if (!isOpen())
    180                 throw new ClosedChannelException();
    181             return remoteAddress;
    182         }
    183     }
    184 
    185     @Override
    186     public <T> DatagramChannel setOption(SocketOption<T> name, T value)
    187         throws IOException
    188     {
    189         if (name == null)
    190             throw new NullPointerException();
    191         if (!supportedOptions().contains(name))
    192             throw new UnsupportedOperationException("'" + name + "' not supported");
    193 
    194         synchronized (stateLock) {
    195             ensureOpen();
    196 
    197             if (name == StandardSocketOptions.IP_TOS) {
    198                 // IPv4 only; no-op for IPv6
    199                 if (family == StandardProtocolFamily.INET) {
    200                     Net.setSocketOption(fd, family, name, value);
    201                 }
    202                 return this;
    203             }
    204 
    205             if (name == StandardSocketOptions.IP_MULTICAST_TTL ||
    206                 name == StandardSocketOptions.IP_MULTICAST_LOOP)
    207             {
    208                 // options are protocol dependent
    209                 Net.setSocketOption(fd, family, name, value);
    210                 return this;
    211             }
    212 
    213             if (name == StandardSocketOptions.IP_MULTICAST_IF) {
    214                 if (value == null)
    215                     throw new IllegalArgumentException("Cannot set IP_MULTICAST_IF to 'null'");
    216                 NetworkInterface interf = (NetworkInterface)value;
    217                 if (family == StandardProtocolFamily.INET6) {
    218                     int index = interf.getIndex();
    219                     if (index == -1)
    220                         throw new IOException("Network interface cannot be identified");
    221                     Net.setInterface6(fd, index);
    222                 } else {
    223                     // need IPv4 address to identify interface
    224                     Inet4Address target = Net.anyInet4Address(interf);
    225                     if (target == null)
    226                         throw new IOException("Network interface not configured for IPv4");
    227                     int targetAddress = Net.inet4AsInt(target);
    228                     Net.setInterface4(fd, targetAddress);
    229                 }
    230                 return this;
    231             }
    232             if (name == StandardSocketOptions.SO_REUSEADDR &&
    233                     Net.useExclusiveBind() && localAddress != null)
    234             {
    235                 reuseAddressEmulated = true;
    236                 this.isReuseAddress = (Boolean)value;
    237             }
    238 
    239             // remaining options don't need any special handling
    240             Net.setSocketOption(fd, Net.UNSPEC, name, value);
    241             return this;
    242         }
    243     }
    244 
    245     @SuppressWarnings("unchecked")
    246     public <T> T getOption(SocketOption<T> name)
    247         throws IOException
    248     {
    249         if (name == null)
    250             throw new NullPointerException();
    251         if (!supportedOptions().contains(name))
    252             throw new UnsupportedOperationException("'" + name + "' not supported");
    253 
    254         synchronized (stateLock) {
    255             ensureOpen();
    256 
    257             if (name == StandardSocketOptions.IP_TOS) {
    258                 // IPv4 only; always return 0 on IPv6
    259                 if (family == StandardProtocolFamily.INET) {
    260                     return (T) Net.getSocketOption(fd, family, name);
    261                 } else {
    262                     return (T) Integer.valueOf(0);
    263                 }
    264             }
    265 
    266             if (name == StandardSocketOptions.IP_MULTICAST_TTL ||
    267                 name == StandardSocketOptions.IP_MULTICAST_LOOP)
    268             {
    269                 return (T) Net.getSocketOption(fd, family, name);
    270             }
    271 
    272             if (name == StandardSocketOptions.IP_MULTICAST_IF) {
    273                 if (family == StandardProtocolFamily.INET) {
    274                     int address = Net.getInterface4(fd);
    275                     if (address == 0)
    276                         return null;    // default interface
    277 
    278                     InetAddress ia = Net.inet4FromInt(address);
    279                     NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
    280                     if (ni == null)
    281                         throw new IOException("Unable to map address to interface");
    282                     return (T) ni;
    283                 } else {
    284                     int index = Net.getInterface6(fd);
    285                     if (index == 0)
    286                         return null;    // default interface
    287 
    288                     NetworkInterface ni = NetworkInterface.getByIndex(index);
    289                     if (ni == null)
    290                         throw new IOException("Unable to map index to interface");
    291                     return (T) ni;
    292                 }
    293             }
    294 
    295             if (name == StandardSocketOptions.SO_REUSEADDR &&
    296                     reuseAddressEmulated)
    297             {
    298                 return (T)Boolean.valueOf(isReuseAddress);
    299             }
    300 
    301             // no special handling
    302             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
    303         }
    304     }
    305 
    306     private static class DefaultOptionsHolder {
    307         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
    308 
    309         private static Set<SocketOption<?>> defaultOptions() {
    310             HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(8);
    311             set.add(StandardSocketOptions.SO_SNDBUF);
    312             set.add(StandardSocketOptions.SO_RCVBUF);
    313             set.add(StandardSocketOptions.SO_REUSEADDR);
    314             set.add(StandardSocketOptions.SO_BROADCAST);
    315             set.add(StandardSocketOptions.IP_TOS);
    316             set.add(StandardSocketOptions.IP_MULTICAST_IF);
    317             set.add(StandardSocketOptions.IP_MULTICAST_TTL);
    318             set.add(StandardSocketOptions.IP_MULTICAST_LOOP);
    319             return Collections.unmodifiableSet(set);
    320         }
    321     }
    322 
    323     public final Set<SocketOption<?>> supportedOptions() {
    324         return DefaultOptionsHolder.defaultOptions;
    325     }
    326 
    327     private void ensureOpen() throws ClosedChannelException {
    328         if (!isOpen())
    329             throw new ClosedChannelException();
    330     }
    331 
    332     private SocketAddress sender;       // Set by receive0 (## ugh)
    333 
    334     public SocketAddress receive(ByteBuffer dst) throws IOException {
    335         if (dst.isReadOnly())
    336             throw new IllegalArgumentException("Read-only buffer");
    337         if (dst == null)
    338             throw new NullPointerException();
    339         // Android-changed : Do not attempt to bind to 0 (or 0.0.0.0) if there hasn't been
    340         // an explicit call to bind() yet. Fail fast and return null.
    341         if (localAddress == null)
    342             return null;
    343         synchronized (readLock) {
    344             ensureOpen();
    345             // Socket was not bound before attempting receive
    346             // if (localAddress() == null)
    347             //     bind(null);
    348             int n = 0;
    349             ByteBuffer bb = null;
    350             try {
    351                 begin();
    352                 if (!isOpen())
    353                     return null;
    354                 SecurityManager security = System.getSecurityManager();
    355                 readerThread = NativeThread.current();
    356                 if (isConnected() || (security == null)) {
    357                     do {
    358                         n = receive(fd, dst);
    359                     } while ((n == IOStatus.INTERRUPTED) && isOpen());
    360                     if (n == IOStatus.UNAVAILABLE)
    361                         return null;
    362                 } else {
    363                     bb = Util.getTemporaryDirectBuffer(dst.remaining());
    364                     for (;;) {
    365                         do {
    366                             n = receive(fd, bb);
    367                         } while ((n == IOStatus.INTERRUPTED) && isOpen());
    368                         if (n == IOStatus.UNAVAILABLE)
    369                             return null;
    370                         InetSocketAddress isa = (InetSocketAddress)sender;
    371                         try {
    372                             security.checkAccept(
    373                                 isa.getAddress().getHostAddress(),
    374                                 isa.getPort());
    375                         } catch (SecurityException se) {
    376                             // Ignore packet
    377                             bb.clear();
    378                             n = 0;
    379                             continue;
    380                         }
    381                         bb.flip();
    382                         dst.put(bb);
    383                         break;
    384                     }
    385                 }
    386                 return sender;
    387             } finally {
    388                 if (bb != null)
    389                     Util.releaseTemporaryDirectBuffer(bb);
    390                 readerThread = 0;
    391                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    392                 assert IOStatus.check(n);
    393             }
    394         }
    395     }
    396 
    397     private int receive(FileDescriptor fd, ByteBuffer dst)
    398         throws IOException
    399     {
    400         int pos = dst.position();
    401         int lim = dst.limit();
    402         assert (pos <= lim);
    403         int rem = (pos <= lim ? lim - pos : 0);
    404         if (dst instanceof DirectBuffer && rem > 0)
    405             return receiveIntoNativeBuffer(fd, dst, rem, pos);
    406 
    407         // Substitute a native buffer. If the supplied buffer is empty
    408         // we must instead use a nonempty buffer, otherwise the call
    409         // will not block waiting for a datagram on some platforms.
    410         int newSize = Math.max(rem, 1);
    411         ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);
    412         try {
    413             BlockGuard.getThreadPolicy().onNetwork();
    414 
    415             int n = receiveIntoNativeBuffer(fd, bb, newSize, 0);
    416             bb.flip();
    417             if (n > 0 && rem > 0)
    418                 dst.put(bb);
    419             return n;
    420         } finally {
    421             Util.releaseTemporaryDirectBuffer(bb);
    422         }
    423     }
    424 
    425     private int receiveIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
    426                                         int rem, int pos)
    427         throws IOException
    428     {
    429         int n = receive0(fd, ((DirectBuffer)bb).address() + pos, rem,
    430                          isConnected());
    431         if (n > 0)
    432             bb.position(pos + n);
    433         return n;
    434     }
    435 
    436     public int send(ByteBuffer src, SocketAddress target)
    437         throws IOException
    438     {
    439         if (src == null)
    440             throw new NullPointerException();
    441 
    442         synchronized (writeLock) {
    443             ensureOpen();
    444             InetSocketAddress isa = Net.checkAddress(target);
    445             InetAddress ia = isa.getAddress();
    446             if (ia == null)
    447                 throw new IOException("Target address not resolved");
    448             synchronized (stateLock) {
    449                 if (!isConnected()) {
    450                     if (target == null)
    451                         throw new NullPointerException();
    452                     SecurityManager sm = System.getSecurityManager();
    453                     if (sm != null) {
    454                         if (ia.isMulticastAddress()) {
    455                             sm.checkMulticast(ia);
    456                         } else {
    457                             sm.checkConnect(ia.getHostAddress(),
    458                                             isa.getPort());
    459                         }
    460                     }
    461                 } else { // Connected case; Check address then write
    462                     if (!target.equals(remoteAddress)) {
    463                         throw new IllegalArgumentException(
    464                             "Connected address not equal to target address");
    465                     }
    466                     return write(src);
    467                 }
    468             }
    469 
    470             int n = 0;
    471             try {
    472                 begin();
    473                 if (!isOpen())
    474                     return 0;
    475                 writerThread = NativeThread.current();
    476                 BlockGuard.getThreadPolicy().onNetwork();
    477 
    478                 do {
    479                     n = send(fd, src, isa);
    480                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
    481 
    482                 synchronized (stateLock) {
    483                     if (isOpen() && (localAddress == null)) {
    484                         localAddress = Net.localAddress(fd);
    485                     }
    486                 }
    487                 return IOStatus.normalize(n);
    488             } finally {
    489                 writerThread = 0;
    490                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    491                 assert IOStatus.check(n);
    492             }
    493         }
    494     }
    495 
    496     private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target)
    497         throws IOException
    498     {
    499         if (src instanceof DirectBuffer)
    500             return sendFromNativeBuffer(fd, src, target);
    501 
    502         // Substitute a native buffer
    503         int pos = src.position();
    504         int lim = src.limit();
    505         assert (pos <= lim);
    506         int rem = (pos <= lim ? lim - pos : 0);
    507 
    508         ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
    509         try {
    510             bb.put(src);
    511             bb.flip();
    512             // Do not update src until we see how many bytes were written
    513             src.position(pos);
    514 
    515             int n = sendFromNativeBuffer(fd, bb, target);
    516             if (n > 0) {
    517                 // now update src
    518                 src.position(pos + n);
    519             }
    520             return n;
    521         } finally {
    522             Util.releaseTemporaryDirectBuffer(bb);
    523         }
    524     }
    525 
    526     private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
    527                                      InetSocketAddress target)
    528         throws IOException
    529     {
    530         int pos = bb.position();
    531         int lim = bb.limit();
    532         assert (pos <= lim);
    533         int rem = (pos <= lim ? lim - pos : 0);
    534 
    535         boolean preferIPv6 = (family != StandardProtocolFamily.INET);
    536         int written;
    537         try {
    538             written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos,
    539                             rem, target.getAddress(), target.getPort());
    540         } catch (PortUnreachableException pue) {
    541             if (isConnected())
    542                 throw pue;
    543             written = rem;
    544         }
    545         if (written > 0)
    546             bb.position(pos + written);
    547         return written;
    548     }
    549 
    550     public int read(ByteBuffer buf) throws IOException {
    551         if (buf == null)
    552             throw new NullPointerException();
    553         synchronized (readLock) {
    554             synchronized (stateLock) {
    555                 ensureOpen();
    556                 if (!isConnected())
    557                     throw new NotYetConnectedException();
    558             }
    559             int n = 0;
    560             try {
    561                 begin();
    562                 if (!isOpen())
    563                     return 0;
    564                 readerThread = NativeThread.current();
    565                 do {
    566                     n = IOUtil.read(fd, buf, -1, nd);
    567                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
    568                 return IOStatus.normalize(n);
    569             } finally {
    570                 readerThread = 0;
    571                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    572                 assert IOStatus.check(n);
    573             }
    574         }
    575     }
    576 
    577     public long read(ByteBuffer[] dsts, int offset, int length)
    578         throws IOException
    579     {
    580         if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
    581             throw new IndexOutOfBoundsException();
    582         synchronized (readLock) {
    583             synchronized (stateLock) {
    584                 ensureOpen();
    585                 if (!isConnected())
    586                     throw new NotYetConnectedException();
    587             }
    588             long n = 0;
    589             try {
    590                 begin();
    591                 if (!isOpen())
    592                     return 0;
    593                 readerThread = NativeThread.current();
    594                 do {
    595                     n = IOUtil.read(fd, dsts, offset, length, nd);
    596                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
    597                 return IOStatus.normalize(n);
    598             } finally {
    599                 readerThread = 0;
    600                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    601                 assert IOStatus.check(n);
    602             }
    603         }
    604     }
    605 
    606     public int write(ByteBuffer buf) throws IOException {
    607         if (buf == null)
    608             throw new NullPointerException();
    609         synchronized (writeLock) {
    610             synchronized (stateLock) {
    611                 ensureOpen();
    612                 if (!isConnected())
    613                     throw new NotYetConnectedException();
    614             }
    615             int n = 0;
    616             try {
    617                 begin();
    618                 if (!isOpen())
    619                     return 0;
    620                 writerThread = NativeThread.current();
    621                 do {
    622                     n = IOUtil.write(fd, buf, -1, nd);
    623                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
    624                 return IOStatus.normalize(n);
    625             } finally {
    626                 writerThread = 0;
    627                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    628                 assert IOStatus.check(n);
    629             }
    630         }
    631     }
    632 
    633     public long write(ByteBuffer[] srcs, int offset, int length)
    634         throws IOException
    635     {
    636         if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
    637             throw new IndexOutOfBoundsException();
    638         synchronized (writeLock) {
    639             synchronized (stateLock) {
    640                 ensureOpen();
    641                 if (!isConnected())
    642                     throw new NotYetConnectedException();
    643             }
    644             long n = 0;
    645             try {
    646                 begin();
    647                 if (!isOpen())
    648                     return 0;
    649                 writerThread = NativeThread.current();
    650                 do {
    651                     n = IOUtil.write(fd, srcs, offset, length, nd);
    652                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
    653                 return IOStatus.normalize(n);
    654             } finally {
    655                 writerThread = 0;
    656                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    657                 assert IOStatus.check(n);
    658             }
    659         }
    660     }
    661 
    662     protected void implConfigureBlocking(boolean block) throws IOException {
    663         IOUtil.configureBlocking(fd, block);
    664     }
    665 
    666     public SocketAddress localAddress() {
    667         synchronized (stateLock) {
    668             return localAddress;
    669         }
    670     }
    671 
    672     public SocketAddress remoteAddress() {
    673         synchronized (stateLock) {
    674             return remoteAddress;
    675         }
    676     }
    677 
    678     @Override
    679     public DatagramChannel bind(SocketAddress local) throws IOException {
    680         synchronized (readLock) {
    681             synchronized (writeLock) {
    682                 synchronized (stateLock) {
    683                     ensureOpen();
    684                     if (localAddress != null)
    685                         throw new AlreadyBoundException();
    686                     InetSocketAddress isa;
    687                     if (local == null) {
    688                         // only Inet4Address allowed with IPv4 socket
    689                         if (family == StandardProtocolFamily.INET) {
    690                             isa = new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0);
    691                         } else {
    692                             isa = new InetSocketAddress(0);
    693                         }
    694                     } else {
    695                         isa = Net.checkAddress(local);
    696 
    697                         // only Inet4Address allowed with IPv4 socket
    698                         if (family == StandardProtocolFamily.INET) {
    699                             InetAddress addr = isa.getAddress();
    700                             if (!(addr instanceof Inet4Address))
    701                                 throw new UnsupportedAddressTypeException();
    702                         }
    703                     }
    704                     SecurityManager sm = System.getSecurityManager();
    705                     if (sm != null) {
    706                         sm.checkListen(isa.getPort());
    707                     }
    708                     Net.bind(family, fd, isa.getAddress(), isa.getPort());
    709                     localAddress = Net.localAddress(fd);
    710                 }
    711             }
    712         }
    713         return this;
    714     }
    715 
    716     public boolean isConnected() {
    717         synchronized (stateLock) {
    718             return (state == ST_CONNECTED);
    719         }
    720     }
    721 
    722     void ensureOpenAndUnconnected() throws IOException { // package-private
    723         synchronized (stateLock) {
    724             if (!isOpen())
    725                 throw new ClosedChannelException();
    726             if (state != ST_UNCONNECTED)
    727                 throw new IllegalStateException("Connect already invoked");
    728         }
    729     }
    730 
    731     @Override
    732     public DatagramChannel connect(SocketAddress sa) throws IOException {
    733         int localPort = 0;
    734 
    735         synchronized(readLock) {
    736             synchronized(writeLock) {
    737                 synchronized (stateLock) {
    738                     ensureOpenAndUnconnected();
    739                     InetSocketAddress isa = Net.checkAddress(sa);
    740                     SecurityManager sm = System.getSecurityManager();
    741                     if (sm != null)
    742                         sm.checkConnect(isa.getAddress().getHostAddress(),
    743                                         isa.getPort());
    744                     int n = Net.connect(family,
    745                                         fd,
    746                                         isa.getAddress(),
    747                                         isa.getPort());
    748                     if (n <= 0)
    749                         throw new Error();      // Can't happen
    750 
    751                     // Connection succeeded; disallow further invocation
    752                     state = ST_CONNECTED;
    753                     remoteAddress = isa;
    754                     sender = isa;
    755                     cachedSenderInetAddress = isa.getAddress();
    756                     cachedSenderPort = isa.getPort();
    757 
    758                     // set or refresh local address
    759                     localAddress = Net.localAddress(fd);
    760                 }
    761             }
    762         }
    763         return this;
    764     }
    765 
    766     public DatagramChannel disconnect() throws IOException {
    767         synchronized(readLock) {
    768             synchronized(writeLock) {
    769                 synchronized (stateLock) {
    770                     if (!isConnected() || !isOpen())
    771                         return this;
    772                     InetSocketAddress isa = remoteAddress;
    773                     SecurityManager sm = System.getSecurityManager();
    774                     if (sm != null)
    775                         sm.checkConnect(isa.getAddress().getHostAddress(),
    776                                         isa.getPort());
    777                     boolean isIPv6 = (family == StandardProtocolFamily.INET6);
    778                     disconnect0(fd, isIPv6);
    779                     remoteAddress = null;
    780                     state = ST_UNCONNECTED;
    781 
    782                     // refresh local address
    783                     localAddress = Net.localAddress(fd);
    784                 }
    785             }
    786         }
    787         return this;
    788     }
    789 
    790     protected void implCloseSelectableChannel() throws IOException {
    791         synchronized (stateLock) {
    792             if (state != ST_KILLED)
    793                 nd.preClose(fd);
    794             ResourceManager.afterUdpClose();
    795 
    796             long th;
    797             if ((th = readerThread) != 0)
    798                 NativeThread.signal(th);
    799             if ((th = writerThread) != 0)
    800                 NativeThread.signal(th);
    801             if (!isRegistered())
    802                 kill();
    803         }
    804     }
    805 
    806     public void kill() throws IOException {
    807         synchronized (stateLock) {
    808             if (state == ST_KILLED)
    809                 return;
    810             if (state == ST_UNINITIALIZED) {
    811                 state = ST_KILLED;
    812                 return;
    813             }
    814             assert !isOpen() && !isRegistered();
    815             nd.close(fd);
    816             state = ST_KILLED;
    817         }
    818     }
    819 
    820     protected void finalize() throws IOException {
    821         // fd is null if constructor threw exception
    822         if (fd != null)
    823             close();
    824     }
    825 
    826     /**
    827      * Translates native poll revent set into a ready operation set
    828      */
    829     public boolean translateReadyOps(int ops, int initialOps,
    830                                      SelectionKeyImpl sk) {
    831         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
    832         int oldOps = sk.nioReadyOps();
    833         int newOps = initialOps;
    834 
    835         if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
    836             // This should only happen if this channel is pre-closed while a
    837             // selection operation is in progress
    838             // ## Throw an error if this channel has not been pre-closed
    839             return false;
    840         }
    841 
    842         if ((ops & (PollArrayWrapper.POLLERR
    843                     | PollArrayWrapper.POLLHUP)) != 0) {
    844             newOps = intOps;
    845             sk.nioReadyOps(newOps);
    846             return (newOps & ~oldOps) != 0;
    847         }
    848 
    849         if (((ops & PollArrayWrapper.POLLIN) != 0) &&
    850             ((intOps & SelectionKey.OP_READ) != 0))
    851             newOps |= SelectionKey.OP_READ;
    852 
    853         if (((ops & PollArrayWrapper.POLLOUT) != 0) &&
    854             ((intOps & SelectionKey.OP_WRITE) != 0))
    855             newOps |= SelectionKey.OP_WRITE;
    856 
    857         sk.nioReadyOps(newOps);
    858         return (newOps & ~oldOps) != 0;
    859     }
    860 
    861     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
    862         return translateReadyOps(ops, sk.nioReadyOps(), sk);
    863     }
    864 
    865     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
    866         return translateReadyOps(ops, 0, sk);
    867     }
    868 
    869     /**
    870      * Translates an interest operation set into a native poll event set
    871      */
    872     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
    873         int newOps = 0;
    874 
    875         if ((ops & SelectionKey.OP_READ) != 0)
    876             newOps |= PollArrayWrapper.POLLIN;
    877         if ((ops & SelectionKey.OP_WRITE) != 0)
    878             newOps |= PollArrayWrapper.POLLOUT;
    879         if ((ops & SelectionKey.OP_CONNECT) != 0)
    880             newOps |= PollArrayWrapper.POLLIN;
    881         sk.selector.putEventOps(sk, newOps);
    882     }
    883 
    884     public FileDescriptor getFD() {
    885         return fd;
    886     }
    887 
    888     public int getFDVal() {
    889         return fdVal;
    890     }
    891 
    892 
    893     // -- Native methods --
    894 
    895     private static native void initIDs();
    896 
    897     private static native void disconnect0(FileDescriptor fd, boolean isIPv6)
    898         throws IOException;
    899 
    900     private native int receive0(FileDescriptor fd, long address, int len,
    901                                 boolean connected)
    902         throws IOException;
    903 
    904     private native int send0(boolean preferIPv6, FileDescriptor fd, long address,
    905                              int len, InetAddress addr, int port)
    906         throws IOException;
    907 
    908     static {
    909         initIDs();
    910     }
    911 
    912 }
    913