1 /*
   2  * Copyright (c) 2001, 2018, 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.DatagramSocket;
  31 import java.net.Inet4Address;
  32 import java.net.Inet6Address;
  33 import java.net.InetAddress;
  34 import java.net.InetSocketAddress;
  35 import java.net.NetworkInterface;
  36 import java.net.PortUnreachableException;
  37 import java.net.ProtocolFamily;
  38 import java.net.SocketAddress;
  39 import java.net.SocketOption;
  40 import java.net.StandardProtocolFamily;
  41 import java.net.StandardSocketOptions;
  42 import java.nio.ByteBuffer;
  43 import java.nio.channels.AlreadyBoundException;
  44 import java.nio.channels.ClosedChannelException;
  45 import java.nio.channels.DatagramChannel;
  46 import java.nio.channels.MembershipKey;
  47 import java.nio.channels.NotYetConnectedException;
  48 import java.nio.channels.SelectionKey;
  49 import java.nio.channels.UnsupportedAddressTypeException;
  50 import java.nio.channels.spi.SelectorProvider;
  51 import java.util.Collections;
  52 import java.util.HashSet;
  53 import java.util.Set;
  54 import java.util.concurrent.locks.ReentrantLock;
  55 
  56 import sun.net.ResourceManager;
  57 import sun.net.ext.ExtendedSocketOptions;
  58 
  59 /**
  60  * An implementation of DatagramChannels.
  61  */
  62 
  63 class DatagramChannelImpl
  64     extends DatagramChannel
  65     implements SelChImpl
  66 {
  67 
  68     // Used to make native read and write calls
  69     private static NativeDispatcher nd = new DatagramDispatcher();
  70 
  71     // Our file descriptor
  72     private final FileDescriptor fd;
  73     private final int fdVal;
  74 
  75     // The protocol family of the socket
  76     private final ProtocolFamily family;
  77 
  78     // IDs of native threads doing reads and writes, for signalling
  79     private volatile long readerThread;
  80     private volatile long writerThread;
  81 
  82     // Cached InetAddress and port for unconnected DatagramChannels
  83     // used by receive0
  84     private InetAddress cachedSenderInetAddress;
  85     private int cachedSenderPort;
  86 
  87     // Lock held by current reading or connecting thread
  88     private final ReentrantLock readLock = new ReentrantLock();
  89 
  90     // Lock held by current writing or connecting thread
  91     private final ReentrantLock writeLock = new ReentrantLock();
  92 
  93     // Lock held by any thread that modifies the state fields declared below
  94     // DO NOT invoke a blocking I/O operation while holding this lock!
  95     private final Object stateLock = new Object();
  96 
  97     // -- The following fields are protected by stateLock
  98 
  99     // State (does not necessarily increase monotonically)
 100     private static final int ST_UNINITIALIZED = -1;
 101     private static final int ST_UNCONNECTED = 0;
 102     private static final int ST_CONNECTED = 1;
 103     private static final int ST_KILLED = 2;
 104     private int state = ST_UNINITIALIZED;
 105 
 106     // Binding
 107     private InetSocketAddress localAddress;
 108     private InetSocketAddress remoteAddress;
 109 
 110     // Our socket adaptor, if any
 111     private DatagramSocket socket;
 112 
 113     // Multicast support
 114     private MembershipRegistry registry;
 115 
 116     // set true when socket is bound and SO_REUSEADDRESS is emulated
 117     private boolean reuseAddressEmulated;
 118 
 119     // set true/false when socket is already bound and SO_REUSEADDR is emulated
 120     private boolean isReuseAddress;
 121 
 122     // -- End of fields protected by stateLock
 123 
 124     public DatagramChannelImpl(SelectorProvider sp)
 125         throws IOException
 126     {
 127         super(sp);
 128         ResourceManager.beforeUdpCreate();
 129         try {
 130             this.family = Net.isIPv6Available() ?
 131                 StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
 132             this.fd = Net.socket(family, false);
 133             this.fdVal = IOUtil.fdVal(fd);
 134             this.state = ST_UNCONNECTED;
 135         } catch (IOException ioe) {
 136             ResourceManager.afterUdpClose();
 137             throw ioe;
 138         }
 139     }
 140 
 141     public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family)
 142         throws IOException
 143     {
 144         super(sp);
 145         if ((family != StandardProtocolFamily.INET) &&
 146             (family != StandardProtocolFamily.INET6))
 147         {
 148             if (family == null)
 149                 throw new NullPointerException("'family' is null");
 150             else
 151                 throw new UnsupportedOperationException("Protocol family not supported");
 152         }
 153         if (family == StandardProtocolFamily.INET6) {
 154             if (!Net.isIPv6Available()) {
 155                 throw new UnsupportedOperationException("IPv6 not available");
 156             }
 157         }
 158 
 159         ResourceManager.beforeUdpCreate();
 160         try {
 161             this.family = family;
 162             this.fd = Net.socket(family, false);
 163             this.fdVal = IOUtil.fdVal(fd);
 164             this.state = ST_UNCONNECTED;
 165         } catch (IOException ioe) {
 166             ResourceManager.afterUdpClose();
 167             throw ioe;
 168         }
 169     }
 170 
 171     public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
 172         throws IOException
 173     {
 174         super(sp);
 175 
 176         // increment UDP count to match decrement when closing
 177         ResourceManager.beforeUdpCreate();
 178 
 179         this.family = Net.isIPv6Available() ?
 180             StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
 181         this.fd = fd;
 182         this.fdVal = IOUtil.fdVal(fd);
 183         this.state = ST_UNCONNECTED;
 184         this.localAddress = Net.localAddress(fd);
 185     }
 186 
 187     public DatagramSocket socket() {
 188         synchronized (stateLock) {
 189             if (socket == null)
 190                 socket = DatagramSocketAdaptor.create(this);
 191             return socket;
 192         }
 193     }
 194 
 195     @Override
 196     public SocketAddress getLocalAddress() throws IOException {
 197         synchronized (stateLock) {
 198             if (!isOpen())
 199                 throw new ClosedChannelException();
 200             // Perform security check before returning address
 201             return Net.getRevealedLocalAddress(localAddress);
 202         }
 203     }
 204 
 205     @Override
 206     public SocketAddress getRemoteAddress() throws IOException {
 207         synchronized (stateLock) {
 208             if (!isOpen())
 209                 throw new ClosedChannelException();
 210             return remoteAddress;
 211         }
 212     }
 213 
 214     @Override
 215     public <T> DatagramChannel setOption(SocketOption<T> name, T value)
 216         throws IOException
 217     {
 218         if (name == null)
 219             throw new NullPointerException();
 220         if (!supportedOptions().contains(name))
 221             throw new UnsupportedOperationException("'" + name + "' not supported");
 222 
 223         synchronized (stateLock) {
 224             ensureOpen();
 225 
 226             if (name == StandardSocketOptions.IP_TOS ||
 227                 name == StandardSocketOptions.IP_MULTICAST_TTL ||
 228                 name == StandardSocketOptions.IP_MULTICAST_LOOP)
 229             {
 230                 // options are protocol dependent
 231                 Net.setSocketOption(fd, family, name, value);
 232                 return this;
 233             }
 234 
 235             if (name == StandardSocketOptions.IP_MULTICAST_IF) {
 236                 if (value == null)
 237                     throw new IllegalArgumentException("Cannot set IP_MULTICAST_IF to 'null'");
 238                 NetworkInterface interf = (NetworkInterface)value;
 239                 if (family == StandardProtocolFamily.INET6) {
 240                     int index = interf.getIndex();
 241                     if (index == -1)
 242                         throw new IOException("Network interface cannot be identified");
 243                     Net.setInterface6(fd, index);
 244                 } else {
 245                     // need IPv4 address to identify interface
 246                     Inet4Address target = Net.anyInet4Address(interf);
 247                     if (target == null)
 248                         throw new IOException("Network interface not configured for IPv4");
 249                     int targetAddress = Net.inet4AsInt(target);
 250                     Net.setInterface4(fd, targetAddress);
 251                 }
 252                 return this;
 253             }
 254             if (name == StandardSocketOptions.SO_REUSEADDR &&
 255                     Net.useExclusiveBind() && localAddress != null)
 256             {
 257                 reuseAddressEmulated = true;
 258                 this.isReuseAddress = (Boolean)value;
 259             }
 260 
 261             // remaining options don't need any special handling
 262             Net.setSocketOption(fd, Net.UNSPEC, name, value);
 263             return this;
 264         }
 265     }
 266 
 267     @Override
 268     @SuppressWarnings("unchecked")
 269     public <T> T getOption(SocketOption<T> name)
 270         throws IOException
 271     {
 272         if (name == null)
 273             throw new NullPointerException();
 274         if (!supportedOptions().contains(name))
 275             throw new UnsupportedOperationException("'" + name + "' not supported");
 276 
 277         synchronized (stateLock) {
 278             ensureOpen();
 279 
 280             if (name == StandardSocketOptions.IP_TOS ||
 281                 name == StandardSocketOptions.IP_MULTICAST_TTL ||
 282                 name == StandardSocketOptions.IP_MULTICAST_LOOP)
 283             {
 284                 return (T) Net.getSocketOption(fd, family, name);
 285             }
 286 
 287             if (name == StandardSocketOptions.IP_MULTICAST_IF) {
 288                 if (family == StandardProtocolFamily.INET) {
 289                     int address = Net.getInterface4(fd);
 290                     if (address == 0)
 291                         return null;    // default interface
 292 
 293                     InetAddress ia = Net.inet4FromInt(address);
 294                     NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
 295                     if (ni == null)
 296                         throw new IOException("Unable to map address to interface");
 297                     return (T) ni;
 298                 } else {
 299                     int index = Net.getInterface6(fd);
 300                     if (index == 0)
 301                         return null;    // default interface
 302 
 303                     NetworkInterface ni = NetworkInterface.getByIndex(index);
 304                     if (ni == null)
 305                         throw new IOException("Unable to map index to interface");
 306                     return (T) ni;
 307                 }
 308             }
 309 
 310             if (name == StandardSocketOptions.SO_REUSEADDR &&
 311                     reuseAddressEmulated)
 312             {
 313                 return (T)Boolean.valueOf(isReuseAddress);
 314             }
 315 
 316             // no special handling
 317             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
 318         }
 319     }
 320 
 321     private static class DefaultOptionsHolder {
 322         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
 323 
 324         private static Set<SocketOption<?>> defaultOptions() {
 325             HashSet<SocketOption<?>> set = new HashSet<>(8);
 326             set.add(StandardSocketOptions.SO_SNDBUF);
 327             set.add(StandardSocketOptions.SO_RCVBUF);
 328             set.add(StandardSocketOptions.SO_REUSEADDR);
 329             if (Net.isReusePortAvailable()) {
 330                 set.add(StandardSocketOptions.SO_REUSEPORT);
 331             }
 332             set.add(StandardSocketOptions.SO_BROADCAST);
 333             set.add(StandardSocketOptions.IP_TOS);
 334             set.add(StandardSocketOptions.IP_MULTICAST_IF);
 335             set.add(StandardSocketOptions.IP_MULTICAST_TTL);
 336             set.add(StandardSocketOptions.IP_MULTICAST_LOOP);
 337             ExtendedSocketOptions extendedOptions =
 338                     ExtendedSocketOptions.getInstance();
 339             set.addAll(extendedOptions.options());
 340             return Collections.unmodifiableSet(set);
 341         }
 342     }
 343 
 344     @Override
 345     public final Set<SocketOption<?>> supportedOptions() {
 346         return DefaultOptionsHolder.defaultOptions;
 347     }
 348 
 349     private void ensureOpen() throws ClosedChannelException {
 350         if (!isOpen())
 351             throw new ClosedChannelException();
 352     }
 353 
 354     private SocketAddress sender;       // Set by receive0 (## ugh)
 355 
 356     public SocketAddress receive(ByteBuffer dst) throws IOException {
 357         if (dst.isReadOnly())
 358             throw new IllegalArgumentException("Read-only buffer");
 359         readLock.lock();
 360         try {
 361             ensureOpen();
 362             // Socket was not bound before attempting receive
 363             if (localAddress() == null)
 364                 bind(null);
 365             int n = 0;
 366             ByteBuffer bb = null;
 367             try {
 368                 begin();
 369                 if (!isOpen())
 370                     return null;
 371                 SecurityManager security = System.getSecurityManager();
 372                 readerThread = NativeThread.current();
 373                 if (isConnected() || (security == null)) {
 374                     do {
 375                         n = receive(fd, dst);
 376                     } while ((n == IOStatus.INTERRUPTED) && isOpen());
 377                     if (n == IOStatus.UNAVAILABLE)
 378                         return null;
 379                 } else {
 380                     // Cannot receive into user's buffer when running with a
 381                     // security manager and not connected
 382                     bb = Util.getTemporaryDirectBuffer(dst.remaining());
 383                     for (;;) {
 384                         do {
 385                             n = receive(fd, bb);
 386                         } while ((n == IOStatus.INTERRUPTED) && isOpen());
 387                         if (n == IOStatus.UNAVAILABLE)
 388                             return null;
 389                         InetSocketAddress isa = (InetSocketAddress)sender;
 390                         try {
 391                             security.checkAccept(
 392                                 isa.getAddress().getHostAddress(),
 393                                 isa.getPort());
 394                         } catch (SecurityException se) {
 395                             // Ignore packet
 396                             bb.clear();
 397                             n = 0;
 398                             continue;
 399                         }
 400                         bb.flip();
 401                         dst.put(bb);
 402                         break;
 403                     }
 404                 }
 405                 return sender;
 406             } finally {
 407                 if (bb != null)
 408                     Util.releaseTemporaryDirectBuffer(bb);
 409                 readerThread = 0;
 410                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 411                 assert IOStatus.check(n);
 412             }
 413         } finally {
 414             readLock.unlock();
 415         }
 416     }
 417 
 418     private int receive(FileDescriptor fd, ByteBuffer dst)
 419         throws IOException
 420     {
 421         int pos = dst.position();
 422         int lim = dst.limit();
 423         assert (pos <= lim);
 424         int rem = (pos <= lim ? lim - pos : 0);
 425         if (dst instanceof DirectBuffer && rem > 0)
 426             return receiveIntoNativeBuffer(fd, dst, rem, pos);
 427 
 428         // Substitute a native buffer. If the supplied buffer is empty
 429         // we must instead use a nonempty buffer, otherwise the call
 430         // will not block waiting for a datagram on some platforms.
 431         int newSize = Math.max(rem, 1);
 432         ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);
 433         try {
 434             int n = receiveIntoNativeBuffer(fd, bb, newSize, 0);
 435             bb.flip();
 436             if (n > 0 && rem > 0)
 437                 dst.put(bb);
 438             return n;
 439         } finally {
 440             Util.releaseTemporaryDirectBuffer(bb);
 441         }
 442     }
 443 
 444     private int receiveIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
 445                                         int rem, int pos)
 446         throws IOException
 447     {
 448         int n = receive0(fd, ((DirectBuffer)bb).address() + pos, rem,
 449                          isConnected());
 450         if (n > 0)
 451             bb.position(pos + n);
 452         return n;
 453     }
 454 
 455     public int send(ByteBuffer src, SocketAddress target)
 456         throws IOException
 457     {
 458         if (src == null)
 459             throw new NullPointerException();
 460 
 461         writeLock.lock();
 462         try {
 463             ensureOpen();
 464             InetSocketAddress isa = Net.checkAddress(target);
 465             InetAddress ia = isa.getAddress();
 466             if (ia == null)
 467                 throw new IOException("Target address not resolved");
 468             synchronized (stateLock) {
 469                 if (!isConnected()) {
 470                     if (target == null)
 471                         throw new NullPointerException();
 472                     SecurityManager sm = System.getSecurityManager();
 473                     if (sm != null) {
 474                         if (ia.isMulticastAddress()) {
 475                             sm.checkMulticast(ia);
 476                         } else {
 477                             sm.checkConnect(ia.getHostAddress(),
 478                                             isa.getPort());
 479                         }
 480                     }
 481                 } else { // Connected case; Check address then write
 482                     if (!target.equals(remoteAddress)) {
 483                         throw new IllegalArgumentException(
 484                             "Connected address not equal to target address");
 485                     }
 486                     return write(src);
 487                 }
 488             }
 489 
 490             int n = 0;
 491             try {
 492                 begin();
 493                 if (!isOpen())
 494                     return 0;
 495                 writerThread = NativeThread.current();
 496                 do {
 497                     n = send(fd, src, isa);
 498                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 499 
 500                 synchronized (stateLock) {
 501                     if (isOpen() && (localAddress == null)) {
 502                         localAddress = Net.localAddress(fd);
 503                     }
 504                 }
 505                 return IOStatus.normalize(n);
 506             } finally {
 507                 writerThread = 0;
 508                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 509                 assert IOStatus.check(n);
 510             }
 511         } finally {
 512             writeLock.unlock();
 513         }
 514     }
 515 
 516     private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target)
 517         throws IOException
 518     {
 519         if (src instanceof DirectBuffer)
 520             return sendFromNativeBuffer(fd, src, target);
 521 
 522         // Substitute a native buffer
 523         int pos = src.position();
 524         int lim = src.limit();
 525         assert (pos <= lim);
 526         int rem = (pos <= lim ? lim - pos : 0);
 527 
 528         ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
 529         try {
 530             bb.put(src);
 531             bb.flip();
 532             // Do not update src until we see how many bytes were written
 533             src.position(pos);
 534 
 535             int n = sendFromNativeBuffer(fd, bb, target);
 536             if (n > 0) {
 537                 // now update src
 538                 src.position(pos + n);
 539             }
 540             return n;
 541         } finally {
 542             Util.releaseTemporaryDirectBuffer(bb);
 543         }
 544     }
 545 
 546     private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
 547                                      InetSocketAddress target)
 548         throws IOException
 549     {
 550         int pos = bb.position();
 551         int lim = bb.limit();
 552         assert (pos <= lim);
 553         int rem = (pos <= lim ? lim - pos : 0);
 554 
 555         boolean preferIPv6 = (family != StandardProtocolFamily.INET);
 556         int written;
 557         try {
 558             written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos,
 559                             rem, target.getAddress(), target.getPort());
 560         } catch (PortUnreachableException pue) {
 561             if (isConnected())
 562                 throw pue;
 563             written = rem;
 564         }
 565         if (written > 0)
 566             bb.position(pos + written);
 567         return written;
 568     }
 569 
 570     public int read(ByteBuffer buf) throws IOException {
 571         if (buf == null)
 572             throw new NullPointerException();
 573         readLock.lock();
 574         try {
 575             synchronized (stateLock) {
 576                 ensureOpen();
 577                 if (!isConnected())
 578                     throw new NotYetConnectedException();
 579             }
 580             int n = 0;
 581             try {
 582                 begin();
 583                 if (!isOpen())
 584                     return 0;
 585                 readerThread = NativeThread.current();
 586                 do {
 587                     n = IOUtil.read(fd, buf, -1, nd);
 588                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 589                 return IOStatus.normalize(n);
 590             } finally {
 591                 readerThread = 0;
 592                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 593                 assert IOStatus.check(n);
 594             }
 595         } finally {
 596             readLock.unlock();
 597         }
 598     }
 599 
 600     public long read(ByteBuffer[] dsts, int offset, int length)
 601         throws IOException
 602     {
 603         if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
 604             throw new IndexOutOfBoundsException();
 605         readLock.lock();
 606         try {
 607             synchronized (stateLock) {
 608                 ensureOpen();
 609                 if (!isConnected())
 610                     throw new NotYetConnectedException();
 611             }
 612             long n = 0;
 613             try {
 614                 begin();
 615                 if (!isOpen())
 616                     return 0;
 617                 readerThread = NativeThread.current();
 618                 do {
 619                     n = IOUtil.read(fd, dsts, offset, length, nd);
 620                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 621                 return IOStatus.normalize(n);
 622             } finally {
 623                 readerThread = 0;
 624                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 625                 assert IOStatus.check(n);
 626             }
 627         } finally {
 628             readLock.unlock();
 629         }
 630     }
 631 
 632     public int write(ByteBuffer buf) throws IOException {
 633         if (buf == null)
 634             throw new NullPointerException();
 635         writeLock.lock();
 636         try {
 637             synchronized (stateLock) {
 638                 ensureOpen();
 639                 if (!isConnected())
 640                     throw new NotYetConnectedException();
 641             }
 642             int n = 0;
 643             try {
 644                 begin();
 645                 if (!isOpen())
 646                     return 0;
 647                 writerThread = NativeThread.current();
 648                 do {
 649                     n = IOUtil.write(fd, buf, -1, nd);
 650                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 651                 return IOStatus.normalize(n);
 652             } finally {
 653                 writerThread = 0;
 654                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 655                 assert IOStatus.check(n);
 656             }
 657         } finally {
 658             writeLock.unlock();
 659         }
 660     }
 661 
 662     public long write(ByteBuffer[] srcs, int offset, int length)
 663         throws IOException
 664     {
 665         if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
 666             throw new IndexOutOfBoundsException();
 667         writeLock.lock();
 668         try {
 669             synchronized (stateLock) {
 670                 ensureOpen();
 671                 if (!isConnected())
 672                     throw new NotYetConnectedException();
 673             }
 674             long n = 0;
 675             try {
 676                 begin();
 677                 if (!isOpen())
 678                     return 0;
 679                 writerThread = NativeThread.current();
 680                 do {
 681                     n = IOUtil.write(fd, srcs, offset, length, nd);
 682                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 683                 return IOStatus.normalize(n);
 684             } finally {
 685                 writerThread = 0;
 686                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 687                 assert IOStatus.check(n);
 688             }
 689         } finally {
 690             writeLock.unlock();
 691         }
 692     }
 693 
 694     protected void implConfigureBlocking(boolean block) throws IOException {
 695         IOUtil.configureBlocking(fd, block);
 696     }
 697 
 698     public SocketAddress localAddress() {
 699         synchronized (stateLock) {
 700             return localAddress;
 701         }
 702     }
 703 
 704     public SocketAddress remoteAddress() {
 705         synchronized (stateLock) {
 706             return remoteAddress;
 707         }
 708     }
 709 
 710     @Override
 711     public DatagramChannel bind(SocketAddress local) throws IOException {
 712         readLock.lock();
 713         try {
 714             writeLock.lock();
 715             try {
 716                 synchronized (stateLock) {
 717                     ensureOpen();
 718                     if (localAddress != null)
 719                         throw new AlreadyBoundException();
 720                     InetSocketAddress isa;
 721                     if (local == null) {
 722                         // only Inet4Address allowed with IPv4 socket
 723                         if (family == StandardProtocolFamily.INET) {
 724                             isa = new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0);
 725                         } else {
 726                             isa = new InetSocketAddress(0);
 727                         }
 728                     } else {
 729                         isa = Net.checkAddress(local);
 730 
 731                         // only Inet4Address allowed with IPv4 socket
 732                         if (family == StandardProtocolFamily.INET) {
 733                             InetAddress addr = isa.getAddress();
 734                             if (!(addr instanceof Inet4Address))
 735                                 throw new UnsupportedAddressTypeException();
 736                         }
 737                     }
 738                     SecurityManager sm = System.getSecurityManager();
 739                     if (sm != null) {
 740                         sm.checkListen(isa.getPort());
 741                     }
 742                     Net.bind(family, fd, isa.getAddress(), isa.getPort());
 743                     localAddress = Net.localAddress(fd);
 744                 }
 745             } finally {
 746                 writeLock.unlock();
 747             }
 748         } finally {
 749             readLock.unlock();
 750         }
 751         return this;
 752     }
 753 
 754     public boolean isConnected() {
 755         synchronized (stateLock) {
 756             return (state == ST_CONNECTED);
 757         }
 758     }
 759 
 760     void ensureOpenAndUnconnected() throws IOException { // package-private
 761         synchronized (stateLock) {
 762             if (!isOpen())
 763                 throw new ClosedChannelException();
 764             if (state != ST_UNCONNECTED)
 765                 throw new IllegalStateException("Connect already invoked");
 766         }
 767     }
 768 
 769     @Override
 770     public DatagramChannel connect(SocketAddress sa) throws IOException {
 771         readLock.lock();
 772         try {
 773             writeLock.lock();
 774             try {
 775                 synchronized (stateLock) {
 776                     ensureOpenAndUnconnected();
 777                     InetSocketAddress isa = Net.checkAddress(sa);
 778                     SecurityManager sm = System.getSecurityManager();
 779                     if (sm != null)
 780                         sm.checkConnect(isa.getAddress().getHostAddress(),
 781                                         isa.getPort());
 782                     int n = Net.connect(family,
 783                                         fd,
 784                                         isa.getAddress(),
 785                                         isa.getPort());
 786                     if (n <= 0)
 787                         throw new Error();      // Can't happen
 788 
 789                     // Connection succeeded; disallow further invocation
 790                     state = ST_CONNECTED;
 791                     remoteAddress = isa;
 792                     sender = isa;
 793                     cachedSenderInetAddress = isa.getAddress();
 794                     cachedSenderPort = isa.getPort();
 795 
 796                     // set or refresh local address
 797                     localAddress = Net.localAddress(fd);
 798 
 799                     // flush any packets already received.
 800                     synchronized (blockingLock()) {
 801                         boolean blocking = isBlocking();
 802                         try {
 803                             ByteBuffer tmpBuf = ByteBuffer.allocate(100);
 804                             if (blocking) {
 805                                 configureBlocking(false);
 806                             }
 807                             do {
 808                                 tmpBuf.clear();
 809                             } while (receive(tmpBuf) != null);
 810                         } finally {
 811                             if (blocking) {
 812                                 configureBlocking(true);
 813                             }
 814                         }
 815                     }
 816                 }
 817             } finally {
 818                 writeLock.unlock();
 819             }
 820         } finally {
 821             readLock.unlock();
 822         }
 823         return this;
 824     }
 825 
 826     public DatagramChannel disconnect() throws IOException {
 827         readLock.lock();
 828         try {
 829             writeLock.lock();
 830             try {
 831                 synchronized (stateLock) {
 832                     if (!isConnected() || !isOpen())
 833                         return this;
 834                     InetSocketAddress isa = remoteAddress;
 835                     SecurityManager sm = System.getSecurityManager();
 836                     if (sm != null)
 837                         sm.checkConnect(isa.getAddress().getHostAddress(),
 838                                         isa.getPort());
 839                     boolean isIPv6 = (family == StandardProtocolFamily.INET6);
 840                     disconnect0(fd, isIPv6);
 841                     remoteAddress = null;
 842                     state = ST_UNCONNECTED;
 843 
 844                     // refresh local address
 845                     localAddress = Net.localAddress(fd);
 846                 }
 847             } finally {
 848                 writeLock.unlock();
 849             }
 850         } finally {
 851             readLock.unlock();
 852         }
 853         return this;
 854     }
 855 
 856     /**
 857      * Joins channel's socket to the given group/interface and
 858      * optional source address.
 859      */
 860     private MembershipKey innerJoin(InetAddress group,
 861                                     NetworkInterface interf,
 862                                     InetAddress source)
 863         throws IOException
 864     {
 865         if (!group.isMulticastAddress())
 866             throw new IllegalArgumentException("Group not a multicast address");
 867 
 868         // check multicast address is compatible with this socket
 869         if (group instanceof Inet4Address) {
 870             if (family == StandardProtocolFamily.INET6 && !Net.canIPv6SocketJoinIPv4Group())
 871                 throw new IllegalArgumentException("IPv6 socket cannot join IPv4 multicast group");
 872         } else if (group instanceof Inet6Address) {
 873             if (family != StandardProtocolFamily.INET6)
 874                 throw new IllegalArgumentException("Only IPv6 sockets can join IPv6 multicast group");
 875         } else {
 876             throw new IllegalArgumentException("Address type not supported");
 877         }
 878 
 879         // check source address
 880         if (source != null) {
 881             if (source.isAnyLocalAddress())
 882                 throw new IllegalArgumentException("Source address is a wildcard address");
 883             if (source.isMulticastAddress())
 884                 throw new IllegalArgumentException("Source address is multicast address");
 885             if (source.getClass() != group.getClass())
 886                 throw new IllegalArgumentException("Source address is different type to group");
 887         }
 888 
 889         SecurityManager sm = System.getSecurityManager();
 890         if (sm != null)
 891             sm.checkMulticast(group);
 892 
 893         synchronized (stateLock) {
 894             if (!isOpen())
 895                 throw new ClosedChannelException();
 896 
 897             // check the registry to see if we are already a member of the group
 898             if (registry == null) {
 899                 registry = new MembershipRegistry();
 900             } else {
 901                 // return existing membership key
 902                 MembershipKey key = registry.checkMembership(group, interf, source);
 903                 if (key != null)
 904                     return key;
 905             }
 906 
 907             MembershipKeyImpl key;
 908             if ((family == StandardProtocolFamily.INET6) &&
 909                 ((group instanceof Inet6Address) || Net.canJoin6WithIPv4Group()))
 910             {
 911                 int index = interf.getIndex();
 912                 if (index == -1)
 913                     throw new IOException("Network interface cannot be identified");
 914 
 915                 // need multicast and source address as byte arrays
 916                 byte[] groupAddress = Net.inet6AsByteArray(group);
 917                 byte[] sourceAddress = (source == null) ? null :
 918                     Net.inet6AsByteArray(source);
 919 
 920                 // join the group
 921                 int n = Net.join6(fd, groupAddress, index, sourceAddress);
 922                 if (n == IOStatus.UNAVAILABLE)
 923                     throw new UnsupportedOperationException();
 924 
 925                 key = new MembershipKeyImpl.Type6(this, group, interf, source,
 926                                                   groupAddress, index, sourceAddress);
 927 
 928             } else {
 929                 // need IPv4 address to identify interface
 930                 Inet4Address target = Net.anyInet4Address(interf);
 931                 if (target == null)
 932                     throw new IOException("Network interface not configured for IPv4");
 933 
 934                 int groupAddress = Net.inet4AsInt(group);
 935                 int targetAddress = Net.inet4AsInt(target);
 936                 int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source);
 937 
 938                 // join the group
 939                 int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress);
 940                 if (n == IOStatus.UNAVAILABLE)
 941                     throw new UnsupportedOperationException();
 942 
 943                 key = new MembershipKeyImpl.Type4(this, group, interf, source,
 944                                                   groupAddress, targetAddress, sourceAddress);
 945             }
 946 
 947             registry.add(key);
 948             return key;
 949         }
 950     }
 951 
 952     @Override
 953     public MembershipKey join(InetAddress group,
 954                               NetworkInterface interf)
 955         throws IOException
 956     {
 957         return innerJoin(group, interf, null);
 958     }
 959 
 960     @Override
 961     public MembershipKey join(InetAddress group,
 962                               NetworkInterface interf,
 963                               InetAddress source)
 964         throws IOException
 965     {
 966         if (source == null)
 967             throw new NullPointerException("source address is null");
 968         return innerJoin(group, interf, source);
 969     }
 970 
 971     // package-private
 972     void drop(MembershipKeyImpl key) {
 973         assert key.channel() == this;
 974 
 975         synchronized (stateLock) {
 976             if (!key.isValid())
 977                 return;
 978 
 979             try {
 980                 if (key instanceof MembershipKeyImpl.Type6) {
 981                     MembershipKeyImpl.Type6 key6 =
 982                         (MembershipKeyImpl.Type6)key;
 983                     Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source());
 984                 } else {
 985                     MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4)key;
 986                     Net.drop4(fd, key4.groupAddress(), key4.interfaceAddress(),
 987                         key4.source());
 988                 }
 989             } catch (IOException ioe) {
 990                 // should not happen
 991                 throw new AssertionError(ioe);
 992             }
 993 
 994             key.invalidate();
 995             registry.remove(key);
 996         }
 997     }
 998 
 999     /**
1000      * Block datagrams from given source if a memory to receive all
1001      * datagrams.
1002      */
1003     void block(MembershipKeyImpl key, InetAddress source)
1004         throws IOException
1005     {
1006         assert key.channel() == this;
1007         assert key.sourceAddress() == null;
1008 
1009         synchronized (stateLock) {
1010             if (!key.isValid())
1011                 throw new IllegalStateException("key is no longer valid");
1012             if (source.isAnyLocalAddress())
1013                 throw new IllegalArgumentException("Source address is a wildcard address");
1014             if (source.isMulticastAddress())
1015                 throw new IllegalArgumentException("Source address is multicast address");
1016             if (source.getClass() != key.group().getClass())
1017                 throw new IllegalArgumentException("Source address is different type to group");
1018 
1019             int n;
1020             if (key instanceof MembershipKeyImpl.Type6) {
1021                  MembershipKeyImpl.Type6 key6 =
1022                     (MembershipKeyImpl.Type6)key;
1023                 n = Net.block6(fd, key6.groupAddress(), key6.index(),
1024                                Net.inet6AsByteArray(source));
1025             } else {
1026                 MembershipKeyImpl.Type4 key4 =
1027                     (MembershipKeyImpl.Type4)key;
1028                 n = Net.block4(fd, key4.groupAddress(), key4.interfaceAddress(),
1029                                Net.inet4AsInt(source));
1030             }
1031             if (n == IOStatus.UNAVAILABLE) {
1032                 // ancient kernel
1033                 throw new UnsupportedOperationException();
1034             }
1035         }
1036     }
1037 
1038     /**
1039      * Unblock given source.
1040      */
1041     void unblock(MembershipKeyImpl key, InetAddress source) {
1042         assert key.channel() == this;
1043         assert key.sourceAddress() == null;
1044 
1045         synchronized (stateLock) {
1046             if (!key.isValid())
1047                 throw new IllegalStateException("key is no longer valid");
1048 
1049             try {
1050                 if (key instanceof MembershipKeyImpl.Type6) {
1051                     MembershipKeyImpl.Type6 key6 =
1052                         (MembershipKeyImpl.Type6)key;
1053                     Net.unblock6(fd, key6.groupAddress(), key6.index(),
1054                                  Net.inet6AsByteArray(source));
1055                 } else {
1056                     MembershipKeyImpl.Type4 key4 =
1057                         (MembershipKeyImpl.Type4)key;
1058                     Net.unblock4(fd, key4.groupAddress(), key4.interfaceAddress(),
1059                                  Net.inet4AsInt(source));
1060                 }
1061             } catch (IOException ioe) {
1062                 // should not happen
1063                 throw new AssertionError(ioe);
1064             }
1065         }
1066     }
1067 
1068     protected void implCloseSelectableChannel() throws IOException {
1069         synchronized (stateLock) {
1070             if (state != ST_KILLED)
1071                 nd.preClose(fd);
1072             ResourceManager.afterUdpClose();
1073 
1074             // if member of mulitcast group then invalidate all keys
1075             if (registry != null)
1076                 registry.invalidateAll();
1077 
1078             long th;
1079             if ((th = readerThread) != 0)
1080                 NativeThread.signal(th);
1081             if ((th = writerThread) != 0)
1082                 NativeThread.signal(th);
1083             if (!isRegistered())
1084                 kill();
1085         }
1086     }
1087 
1088     public void kill() throws IOException {
1089         synchronized (stateLock) {
1090             if (state == ST_KILLED)
1091                 return;
1092             if (state == ST_UNINITIALIZED) {
1093                 state = ST_KILLED;
1094                 return;
1095             }
1096             assert !isOpen() && !isRegistered();
1097             nd.close(fd);
1098             state = ST_KILLED;
1099         }
1100     }
1101 
1102     @SuppressWarnings("deprecation")
1103     protected void finalize() throws IOException {
1104         // fd is null if constructor threw exception
1105         if (fd != null)
1106             close();
1107     }
1108 
1109     /**
1110      * Translates native poll revent set into a ready operation set
1111      */
1112     public boolean translateReadyOps(int ops, int initialOps,
1113                                      SelectionKeyImpl sk) {
1114         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
1115         int oldOps = sk.nioReadyOps();
1116         int newOps = initialOps;
1117 
1118         if ((ops & Net.POLLNVAL) != 0) {
1119             // This should only happen if this channel is pre-closed while a
1120             // selection operation is in progress
1121             // ## Throw an error if this channel has not been pre-closed
1122             return false;
1123         }
1124 
1125         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
1126             newOps = intOps;
1127             sk.nioReadyOps(newOps);
1128             return (newOps & ~oldOps) != 0;
1129         }
1130 
1131         if (((ops & Net.POLLIN) != 0) &&
1132             ((intOps & SelectionKey.OP_READ) != 0))
1133             newOps |= SelectionKey.OP_READ;
1134 
1135         if (((ops & Net.POLLOUT) != 0) &&
1136             ((intOps & SelectionKey.OP_WRITE) != 0))
1137             newOps |= SelectionKey.OP_WRITE;
1138 
1139         sk.nioReadyOps(newOps);
1140         return (newOps & ~oldOps) != 0;
1141     }
1142 
1143     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
1144         return translateReadyOps(ops, sk.nioReadyOps(), sk);
1145     }
1146 
1147     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
1148         return translateReadyOps(ops, 0, sk);
1149     }
1150 
1151     // package-private
1152     int poll(int events, long timeout) throws IOException {
1153         assert Thread.holdsLock(blockingLock()) && !isBlocking();
1154 
1155         readLock.lock();
1156         try {
1157             int n = 0;
1158             try {
1159                 begin();
1160                 synchronized (stateLock) {
1161                     if (!isOpen())
1162                         return 0;
1163                     readerThread = NativeThread.current();
1164                 }
1165                 n = Net.poll(fd, events, timeout);
1166             } finally {
1167                 readerThread = 0;
1168                 end(n > 0);
1169             }
1170             return n;
1171         } finally {
1172             readLock.unlock();
1173         }
1174     }
1175 
1176     /**
1177      * Translates an interest operation set into a native poll event set
1178      */
1179     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
1180         int newOps = 0;
1181 
1182         if ((ops & SelectionKey.OP_READ) != 0)
1183             newOps |= Net.POLLIN;
1184         if ((ops & SelectionKey.OP_WRITE) != 0)
1185             newOps |= Net.POLLOUT;
1186         if ((ops & SelectionKey.OP_CONNECT) != 0)
1187             newOps |= Net.POLLIN;
1188         sk.selector.putEventOps(sk, newOps);
1189     }
1190 
1191     public FileDescriptor getFD() {
1192         return fd;
1193     }
1194 
1195     public int getFDVal() {
1196         return fdVal;
1197     }
1198 
1199 
1200     // -- Native methods --
1201 
1202     private static native void initIDs();
1203 
1204     private static native void disconnect0(FileDescriptor fd, boolean isIPv6)
1205         throws IOException;
1206 
1207     private native int receive0(FileDescriptor fd, long address, int len,
1208                                 boolean connected)
1209         throws IOException;
1210 
1211     private native int send0(boolean preferIPv6, FileDescriptor fd, long address,
1212                              int len, InetAddress addr, int port)
1213         throws IOException;
1214 
1215     static {
1216         IOUtil.load();
1217         initIDs();
1218     }
1219 
1220 }