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