1 /*
   2  * Copyright (c) 2001, 2013, 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.ExtendedOptionsImpl;
  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 = 0;
  62     private volatile long writerThread = 0;
  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             set.add(StandardSocketOptions.SO_BROADCAST);
 302             set.add(StandardSocketOptions.IP_TOS);
 303             set.add(StandardSocketOptions.IP_MULTICAST_IF);
 304             set.add(StandardSocketOptions.IP_MULTICAST_TTL);
 305             set.add(StandardSocketOptions.IP_MULTICAST_LOOP);
 306             if (ExtendedOptionsImpl.flowSupported()) {
 307                 set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA);
 308             }
 309             return Collections.unmodifiableSet(set);
 310         }
 311     }
 312 
 313     @Override
 314     public final Set<SocketOption<?>> supportedOptions() {
 315         return DefaultOptionsHolder.defaultOptions;
 316     }
 317 
 318     private void ensureOpen() throws ClosedChannelException {
 319         if (!isOpen())
 320             throw new ClosedChannelException();
 321     }
 322 
 323     private SocketAddress sender;       // Set by receive0 (## ugh)
 324 
 325     public SocketAddress receive(ByteBuffer dst) throws IOException {
 326         if (dst.isReadOnly())
 327             throw new IllegalArgumentException("Read-only buffer");
 328         if (dst == null)
 329             throw new NullPointerException();
 330         synchronized (readLock) {
 331             ensureOpen();
 332             // Socket was not bound before attempting receive
 333             if (localAddress() == null)
 334                 bind(null);
 335             int n = 0;
 336             ByteBuffer bb = null;
 337             try {
 338                 begin();
 339                 if (!isOpen())
 340                     return null;
 341                 SecurityManager security = System.getSecurityManager();
 342                 readerThread = NativeThread.current();
 343                 if (isConnected() || (security == null)) {
 344                     do {
 345                         n = receive(fd, dst);
 346                     } while ((n == IOStatus.INTERRUPTED) && isOpen());
 347                     if (n == IOStatus.UNAVAILABLE)
 348                         return null;
 349                 } else {
 350                     bb = Util.getTemporaryDirectBuffer(dst.remaining());
 351                     for (;;) {
 352                         do {
 353                             n = receive(fd, bb);
 354                         } while ((n == IOStatus.INTERRUPTED) && isOpen());
 355                         if (n == IOStatus.UNAVAILABLE)
 356                             return null;
 357                         InetSocketAddress isa = (InetSocketAddress)sender;
 358                         try {
 359                             security.checkAccept(
 360                                 isa.getAddress().getHostAddress(),
 361                                 isa.getPort());
 362                         } catch (SecurityException se) {
 363                             // Ignore packet
 364                             bb.clear();
 365                             n = 0;
 366                             continue;
 367                         }
 368                         bb.flip();
 369                         dst.put(bb);
 370                         break;
 371                     }
 372                 }
 373                 return sender;
 374             } finally {
 375                 if (bb != null)
 376                     Util.releaseTemporaryDirectBuffer(bb);
 377                 readerThread = 0;
 378                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 379                 assert IOStatus.check(n);
 380             }
 381         }
 382     }
 383 
 384     private int receive(FileDescriptor fd, ByteBuffer dst)
 385         throws IOException
 386     {
 387         int pos = dst.position();
 388         int lim = dst.limit();
 389         assert (pos <= lim);
 390         int rem = (pos <= lim ? lim - pos : 0);
 391         if (dst instanceof DirectBuffer && rem > 0)
 392             return receiveIntoNativeBuffer(fd, dst, rem, pos);
 393 
 394         // Substitute a native buffer. If the supplied buffer is empty
 395         // we must instead use a nonempty buffer, otherwise the call
 396         // will not block waiting for a datagram on some platforms.
 397         int newSize = Math.max(rem, 1);
 398         ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);
 399         try {
 400             int n = receiveIntoNativeBuffer(fd, bb, newSize, 0);
 401             bb.flip();
 402             if (n > 0 && rem > 0)
 403                 dst.put(bb);
 404             return n;
 405         } finally {
 406             Util.releaseTemporaryDirectBuffer(bb);
 407         }
 408     }
 409 
 410     private int receiveIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
 411                                         int rem, int pos)
 412         throws IOException
 413     {
 414         int n = receive0(fd, ((DirectBuffer)bb).address() + pos, rem,
 415                          isConnected());
 416         if (n > 0)
 417             bb.position(pos + n);
 418         return n;
 419     }
 420 
 421     public int send(ByteBuffer src, SocketAddress target)
 422         throws IOException
 423     {
 424         if (src == null)
 425             throw new NullPointerException();
 426 
 427         synchronized (writeLock) {
 428             ensureOpen();
 429             InetSocketAddress isa = Net.checkAddress(target);
 430             InetAddress ia = isa.getAddress();
 431             if (ia == null)
 432                 throw new IOException("Target address not resolved");
 433             synchronized (stateLock) {
 434                 if (!isConnected()) {
 435                     if (target == null)
 436                         throw new NullPointerException();
 437                     SecurityManager sm = System.getSecurityManager();
 438                     if (sm != null) {
 439                         if (ia.isMulticastAddress()) {
 440                             sm.checkMulticast(ia);
 441                         } else {
 442                             sm.checkConnect(ia.getHostAddress(),
 443                                             isa.getPort());
 444                         }
 445                     }
 446                 } else { // Connected case; Check address then write
 447                     if (!target.equals(remoteAddress)) {
 448                         throw new IllegalArgumentException(
 449                             "Connected address not equal to target address");
 450                     }
 451                     return write(src);
 452                 }
 453             }
 454 
 455             int n = 0;
 456             try {
 457                 begin();
 458                 if (!isOpen())
 459                     return 0;
 460                 writerThread = NativeThread.current();
 461                 do {
 462                     n = send(fd, src, isa);
 463                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 464 
 465                 synchronized (stateLock) {
 466                     if (isOpen() && (localAddress == null)) {
 467                         localAddress = Net.localAddress(fd);
 468                     }
 469                 }
 470                 return IOStatus.normalize(n);
 471             } finally {
 472                 writerThread = 0;
 473                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 474                 assert IOStatus.check(n);
 475             }
 476         }
 477     }
 478 
 479     private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target)
 480         throws IOException
 481     {
 482         if (src instanceof DirectBuffer)
 483             return sendFromNativeBuffer(fd, src, target);
 484 
 485         // Substitute a native buffer
 486         int pos = src.position();
 487         int lim = src.limit();
 488         assert (pos <= lim);
 489         int rem = (pos <= lim ? lim - pos : 0);
 490 
 491         ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
 492         try {
 493             bb.put(src);
 494             bb.flip();
 495             // Do not update src until we see how many bytes were written
 496             src.position(pos);
 497 
 498             int n = sendFromNativeBuffer(fd, bb, target);
 499             if (n > 0) {
 500                 // now update src
 501                 src.position(pos + n);
 502             }
 503             return n;
 504         } finally {
 505             Util.releaseTemporaryDirectBuffer(bb);
 506         }
 507     }
 508 
 509     private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
 510                                      InetSocketAddress target)
 511         throws IOException
 512     {
 513         int pos = bb.position();
 514         int lim = bb.limit();
 515         assert (pos <= lim);
 516         int rem = (pos <= lim ? lim - pos : 0);
 517 
 518         boolean preferIPv6 = (family != StandardProtocolFamily.INET);
 519         int written;
 520         try {
 521             written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos,
 522                             rem, target.getAddress(), target.getPort());
 523         } catch (PortUnreachableException pue) {
 524             if (isConnected())
 525                 throw pue;
 526             written = rem;
 527         }
 528         if (written > 0)
 529             bb.position(pos + written);
 530         return written;
 531     }
 532 
 533     public int read(ByteBuffer buf) throws IOException {
 534         if (buf == null)
 535             throw new NullPointerException();
 536         synchronized (readLock) {
 537             synchronized (stateLock) {
 538                 ensureOpen();
 539                 if (!isConnected())
 540                     throw new NotYetConnectedException();
 541             }
 542             int n = 0;
 543             try {
 544                 begin();
 545                 if (!isOpen())
 546                     return 0;
 547                 readerThread = NativeThread.current();
 548                 do {
 549                     n = IOUtil.read(fd, buf, -1, nd);
 550                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 551                 return IOStatus.normalize(n);
 552             } finally {
 553                 readerThread = 0;
 554                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 555                 assert IOStatus.check(n);
 556             }
 557         }
 558     }
 559 
 560     public long read(ByteBuffer[] dsts, int offset, int length)
 561         throws IOException
 562     {
 563         if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
 564             throw new IndexOutOfBoundsException();
 565         synchronized (readLock) {
 566             synchronized (stateLock) {
 567                 ensureOpen();
 568                 if (!isConnected())
 569                     throw new NotYetConnectedException();
 570             }
 571             long n = 0;
 572             try {
 573                 begin();
 574                 if (!isOpen())
 575                     return 0;
 576                 readerThread = NativeThread.current();
 577                 do {
 578                     n = IOUtil.read(fd, dsts, offset, length, nd);
 579                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 580                 return IOStatus.normalize(n);
 581             } finally {
 582                 readerThread = 0;
 583                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 584                 assert IOStatus.check(n);
 585             }
 586         }
 587     }
 588 
 589     public int write(ByteBuffer buf) throws IOException {
 590         if (buf == null)
 591             throw new NullPointerException();
 592         synchronized (writeLock) {
 593             synchronized (stateLock) {
 594                 ensureOpen();
 595                 if (!isConnected())
 596                     throw new NotYetConnectedException();
 597             }
 598             int n = 0;
 599             try {
 600                 begin();
 601                 if (!isOpen())
 602                     return 0;
 603                 writerThread = NativeThread.current();
 604                 do {
 605                     n = IOUtil.write(fd, buf, -1, nd);
 606                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 607                 return IOStatus.normalize(n);
 608             } finally {
 609                 writerThread = 0;
 610                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 611                 assert IOStatus.check(n);
 612             }
 613         }
 614     }
 615 
 616     public long write(ByteBuffer[] srcs, int offset, int length)
 617         throws IOException
 618     {
 619         if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
 620             throw new IndexOutOfBoundsException();
 621         synchronized (writeLock) {
 622             synchronized (stateLock) {
 623                 ensureOpen();
 624                 if (!isConnected())
 625                     throw new NotYetConnectedException();
 626             }
 627             long n = 0;
 628             try {
 629                 begin();
 630                 if (!isOpen())
 631                     return 0;
 632                 writerThread = NativeThread.current();
 633                 do {
 634                     n = IOUtil.write(fd, srcs, offset, length, nd);
 635                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
 636                 return IOStatus.normalize(n);
 637             } finally {
 638                 writerThread = 0;
 639                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 640                 assert IOStatus.check(n);
 641             }
 642         }
 643     }
 644 
 645     protected void implConfigureBlocking(boolean block) throws IOException {
 646         IOUtil.configureBlocking(fd, block);
 647     }
 648 
 649     public SocketAddress localAddress() {
 650         synchronized (stateLock) {
 651             return localAddress;
 652         }
 653     }
 654 
 655     public SocketAddress remoteAddress() {
 656         synchronized (stateLock) {
 657             return remoteAddress;
 658         }
 659     }
 660 
 661     @Override
 662     public DatagramChannel bind(SocketAddress local) throws IOException {
 663         synchronized (readLock) {
 664             synchronized (writeLock) {
 665                 synchronized (stateLock) {
 666                     ensureOpen();
 667                     if (localAddress != null)
 668                         throw new AlreadyBoundException();
 669                     InetSocketAddress isa;
 670                     if (local == null) {
 671                         // only Inet4Address allowed with IPv4 socket
 672                         if (family == StandardProtocolFamily.INET) {
 673                             isa = new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0);
 674                         } else {
 675                             isa = new InetSocketAddress(0);
 676                         }
 677                     } else {
 678                         isa = Net.checkAddress(local);
 679 
 680                         // only Inet4Address allowed with IPv4 socket
 681                         if (family == StandardProtocolFamily.INET) {
 682                             InetAddress addr = isa.getAddress();
 683                             if (!(addr instanceof Inet4Address))
 684                                 throw new UnsupportedAddressTypeException();
 685                         }
 686                     }
 687                     SecurityManager sm = System.getSecurityManager();
 688                     if (sm != null) {
 689                         sm.checkListen(isa.getPort());
 690                     }
 691                     Net.bind(family, fd, isa.getAddress(), isa.getPort());
 692                     localAddress = Net.localAddress(fd);
 693                 }
 694             }
 695         }
 696         return this;
 697     }
 698 
 699     public boolean isConnected() {
 700         synchronized (stateLock) {
 701             return (state == ST_CONNECTED);
 702         }
 703     }
 704 
 705     void ensureOpenAndUnconnected() throws IOException { // package-private
 706         synchronized (stateLock) {
 707             if (!isOpen())
 708                 throw new ClosedChannelException();
 709             if (state != ST_UNCONNECTED)
 710                 throw new IllegalStateException("Connect already invoked");
 711         }
 712     }
 713 
 714     @Override
 715     public DatagramChannel connect(SocketAddress sa) throws IOException {
 716         int localPort = 0;
 717 
 718         synchronized(readLock) {
 719             synchronized(writeLock) {
 720                 synchronized (stateLock) {
 721                     ensureOpenAndUnconnected();
 722                     InetSocketAddress isa = Net.checkAddress(sa);
 723                     SecurityManager sm = System.getSecurityManager();
 724                     if (sm != null)
 725                         sm.checkConnect(isa.getAddress().getHostAddress(),
 726                                         isa.getPort());
 727                     int n = Net.connect(family,
 728                                         fd,
 729                                         isa.getAddress(),
 730                                         isa.getPort());
 731                     if (n <= 0)
 732                         throw new Error();      // Can't happen
 733 
 734                     // Connection succeeded; disallow further invocation
 735                     state = ST_CONNECTED;
 736                     remoteAddress = isa;
 737                     sender = isa;
 738                     cachedSenderInetAddress = isa.getAddress();
 739                     cachedSenderPort = isa.getPort();
 740 
 741                     // set or refresh local address
 742                     localAddress = Net.localAddress(fd);
 743 
 744                     // flush any packets already received.
 745                     boolean blocking = false;
 746                     synchronized (blockingLock()) {
 747                         try {
 748                             blocking = isBlocking();
 749                             ByteBuffer tmpBuf = ByteBuffer.allocate(100);
 750                             if (blocking) {
 751                                 configureBlocking(false);
 752                             }
 753                             do {
 754                                 tmpBuf.clear();
 755                             } while (receive(tmpBuf) != null);
 756                         } finally {
 757                             if (blocking) {
 758                                 configureBlocking(true);
 759                             }
 760                         }
 761                     }
 762                 }
 763             }
 764         }
 765         return this;
 766     }
 767 
 768     public DatagramChannel disconnect() throws IOException {
 769         synchronized(readLock) {
 770             synchronized(writeLock) {
 771                 synchronized (stateLock) {
 772                     if (!isConnected() || !isOpen())
 773                         return this;
 774                     InetSocketAddress isa = remoteAddress;
 775                     SecurityManager sm = System.getSecurityManager();
 776                     if (sm != null)
 777                         sm.checkConnect(isa.getAddress().getHostAddress(),
 778                                         isa.getPort());
 779                     boolean isIPv6 = (family == StandardProtocolFamily.INET6);
 780                     disconnect0(fd, isIPv6);
 781                     remoteAddress = null;
 782                     state = ST_UNCONNECTED;
 783 
 784                     // refresh local address
 785                     localAddress = Net.localAddress(fd);
 786                 }
 787             }
 788         }
 789         return this;
 790     }
 791 
 792     /**
 793      * Joins channel's socket to the given group/interface and
 794      * optional source address.
 795      */
 796     private MembershipKey innerJoin(InetAddress group,
 797                                     NetworkInterface interf,
 798                                     InetAddress source)
 799         throws IOException
 800     {
 801         if (!group.isMulticastAddress())
 802             throw new IllegalArgumentException("Group not a multicast address");
 803 
 804         // check multicast address is compatible with this socket
 805         if (group instanceof Inet4Address) {
 806             if (family == StandardProtocolFamily.INET6 && !Net.canIPv6SocketJoinIPv4Group())
 807                 throw new IllegalArgumentException("IPv6 socket cannot join IPv4 multicast group");
 808         } else if (group instanceof Inet6Address) {
 809             if (family != StandardProtocolFamily.INET6)
 810                 throw new IllegalArgumentException("Only IPv6 sockets can join IPv6 multicast group");
 811         } else {
 812             throw new IllegalArgumentException("Address type not supported");
 813         }
 814 
 815         // check source address
 816         if (source != null) {
 817             if (source.isAnyLocalAddress())
 818                 throw new IllegalArgumentException("Source address is a wildcard address");
 819             if (source.isMulticastAddress())
 820                 throw new IllegalArgumentException("Source address is multicast address");
 821             if (source.getClass() != group.getClass())
 822                 throw new IllegalArgumentException("Source address is different type to group");
 823         }
 824 
 825         SecurityManager sm = System.getSecurityManager();
 826         if (sm != null)
 827             sm.checkMulticast(group);
 828 
 829         synchronized (stateLock) {
 830             if (!isOpen())
 831                 throw new ClosedChannelException();
 832 
 833             // check the registry to see if we are already a member of the group
 834             if (registry == null) {
 835                 registry = new MembershipRegistry();
 836             } else {
 837                 // return existing membership key
 838                 MembershipKey key = registry.checkMembership(group, interf, source);
 839                 if (key != null)
 840                     return key;
 841             }
 842 
 843             MembershipKeyImpl key;
 844             if ((family == StandardProtocolFamily.INET6) &&
 845                 ((group instanceof Inet6Address) || Net.canJoin6WithIPv4Group()))
 846             {
 847                 int index = interf.getIndex();
 848                 if (index == -1)
 849                     throw new IOException("Network interface cannot be identified");
 850 
 851                 // need multicast and source address as byte arrays
 852                 byte[] groupAddress = Net.inet6AsByteArray(group);
 853                 byte[] sourceAddress = (source == null) ? null :
 854                     Net.inet6AsByteArray(source);
 855 
 856                 // join the group
 857                 int n = Net.join6(fd, groupAddress, index, sourceAddress);
 858                 if (n == IOStatus.UNAVAILABLE)
 859                     throw new UnsupportedOperationException();
 860 
 861                 key = new MembershipKeyImpl.Type6(this, group, interf, source,
 862                                                   groupAddress, index, sourceAddress);
 863 
 864             } else {
 865                 // need IPv4 address to identify interface
 866                 Inet4Address target = Net.anyInet4Address(interf);
 867                 if (target == null)
 868                     throw new IOException("Network interface not configured for IPv4");
 869 
 870                 int groupAddress = Net.inet4AsInt(group);
 871                 int targetAddress = Net.inet4AsInt(target);
 872                 int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source);
 873 
 874                 // join the group
 875                 int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress);
 876                 if (n == IOStatus.UNAVAILABLE)
 877                     throw new UnsupportedOperationException();
 878 
 879                 key = new MembershipKeyImpl.Type4(this, group, interf, source,
 880                                                   groupAddress, targetAddress, sourceAddress);
 881             }
 882 
 883             registry.add(key);
 884             return key;
 885         }
 886     }
 887 
 888     @Override
 889     public MembershipKey join(InetAddress group,
 890                               NetworkInterface interf)
 891         throws IOException
 892     {
 893         return innerJoin(group, interf, null);
 894     }
 895 
 896     @Override
 897     public MembershipKey join(InetAddress group,
 898                               NetworkInterface interf,
 899                               InetAddress source)
 900         throws IOException
 901     {
 902         if (source == null)
 903             throw new NullPointerException("source address is null");
 904         return innerJoin(group, interf, source);
 905     }
 906 
 907     // package-private
 908     void drop(MembershipKeyImpl key) {
 909         assert key.channel() == this;
 910 
 911         synchronized (stateLock) {
 912             if (!key.isValid())
 913                 return;
 914 
 915             try {
 916                 if (key instanceof MembershipKeyImpl.Type6) {
 917                     MembershipKeyImpl.Type6 key6 =
 918                         (MembershipKeyImpl.Type6)key;
 919                     Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source());
 920                 } else {
 921                     MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4)key;
 922                     Net.drop4(fd, key4.groupAddress(), key4.interfaceAddress(),
 923                         key4.source());
 924                 }
 925             } catch (IOException ioe) {
 926                 // should not happen
 927                 throw new AssertionError(ioe);
 928             }
 929 
 930             key.invalidate();
 931             registry.remove(key);
 932         }
 933     }
 934 
 935     /**
 936      * Block datagrams from given source if a memory to receive all
 937      * datagrams.
 938      */
 939     void block(MembershipKeyImpl key, InetAddress source)
 940         throws IOException
 941     {
 942         assert key.channel() == this;
 943         assert key.sourceAddress() == null;
 944 
 945         synchronized (stateLock) {
 946             if (!key.isValid())
 947                 throw new IllegalStateException("key is no longer valid");
 948             if (source.isAnyLocalAddress())
 949                 throw new IllegalArgumentException("Source address is a wildcard address");
 950             if (source.isMulticastAddress())
 951                 throw new IllegalArgumentException("Source address is multicast address");
 952             if (source.getClass() != key.group().getClass())
 953                 throw new IllegalArgumentException("Source address is different type to group");
 954 
 955             int n;
 956             if (key instanceof MembershipKeyImpl.Type6) {
 957                  MembershipKeyImpl.Type6 key6 =
 958                     (MembershipKeyImpl.Type6)key;
 959                 n = Net.block6(fd, key6.groupAddress(), key6.index(),
 960                                Net.inet6AsByteArray(source));
 961             } else {
 962                 MembershipKeyImpl.Type4 key4 =
 963                     (MembershipKeyImpl.Type4)key;
 964                 n = Net.block4(fd, key4.groupAddress(), key4.interfaceAddress(),
 965                                Net.inet4AsInt(source));
 966             }
 967             if (n == IOStatus.UNAVAILABLE) {
 968                 // ancient kernel
 969                 throw new UnsupportedOperationException();
 970             }
 971         }
 972     }
 973 
 974     /**
 975      * Unblock given source.
 976      */
 977     void unblock(MembershipKeyImpl key, InetAddress source) {
 978         assert key.channel() == this;
 979         assert key.sourceAddress() == null;
 980 
 981         synchronized (stateLock) {
 982             if (!key.isValid())
 983                 throw new IllegalStateException("key is no longer valid");
 984 
 985             try {
 986                 if (key instanceof MembershipKeyImpl.Type6) {
 987                     MembershipKeyImpl.Type6 key6 =
 988                         (MembershipKeyImpl.Type6)key;
 989                     Net.unblock6(fd, key6.groupAddress(), key6.index(),
 990                                  Net.inet6AsByteArray(source));
 991                 } else {
 992                     MembershipKeyImpl.Type4 key4 =
 993                         (MembershipKeyImpl.Type4)key;
 994                     Net.unblock4(fd, key4.groupAddress(), key4.interfaceAddress(),
 995                                  Net.inet4AsInt(source));
 996                 }
 997             } catch (IOException ioe) {
 998                 // should not happen
 999                 throw new AssertionError(ioe);
1000             }
1001         }
1002     }
1003 
1004     protected void implCloseSelectableChannel() throws IOException {
1005         synchronized (stateLock) {
1006             if (state != ST_KILLED)
1007                 nd.preClose(fd);
1008             ResourceManager.afterUdpClose();
1009 
1010             // if member of mulitcast group then invalidate all keys
1011             if (registry != null)
1012                 registry.invalidateAll();
1013 
1014             long th;
1015             if ((th = readerThread) != 0)
1016                 NativeThread.signal(th);
1017             if ((th = writerThread) != 0)
1018                 NativeThread.signal(th);
1019             if (!isRegistered())
1020                 kill();
1021         }
1022     }
1023 
1024     public void kill() throws IOException {
1025         synchronized (stateLock) {
1026             if (state == ST_KILLED)
1027                 return;
1028             if (state == ST_UNINITIALIZED) {
1029                 state = ST_KILLED;
1030                 return;
1031             }
1032             assert !isOpen() && !isRegistered();
1033             nd.close(fd);
1034             state = ST_KILLED;
1035         }
1036     }
1037 
1038     protected void finalize() throws IOException {
1039         // fd is null if constructor threw exception
1040         if (fd != null)
1041             close();
1042     }
1043 
1044     /**
1045      * Translates native poll revent set into a ready operation set
1046      */
1047     public boolean translateReadyOps(int ops, int initialOps,
1048                                      SelectionKeyImpl sk) {
1049         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
1050         int oldOps = sk.nioReadyOps();
1051         int newOps = initialOps;
1052 
1053         if ((ops & Net.POLLNVAL) != 0) {
1054             // This should only happen if this channel is pre-closed while a
1055             // selection operation is in progress
1056             // ## Throw an error if this channel has not been pre-closed
1057             return false;
1058         }
1059 
1060         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
1061             newOps = intOps;
1062             sk.nioReadyOps(newOps);
1063             return (newOps & ~oldOps) != 0;
1064         }
1065 
1066         if (((ops & Net.POLLIN) != 0) &&
1067             ((intOps & SelectionKey.OP_READ) != 0))
1068             newOps |= SelectionKey.OP_READ;
1069 
1070         if (((ops & Net.POLLOUT) != 0) &&
1071             ((intOps & SelectionKey.OP_WRITE) != 0))
1072             newOps |= SelectionKey.OP_WRITE;
1073 
1074         sk.nioReadyOps(newOps);
1075         return (newOps & ~oldOps) != 0;
1076     }
1077 
1078     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
1079         return translateReadyOps(ops, sk.nioReadyOps(), sk);
1080     }
1081 
1082     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
1083         return translateReadyOps(ops, 0, sk);
1084     }
1085 
1086     // package-private
1087     int poll(int events, long timeout) throws IOException {
1088         assert Thread.holdsLock(blockingLock()) && !isBlocking();
1089 
1090         synchronized (readLock) {
1091             int n = 0;
1092             try {
1093                 begin();
1094                 synchronized (stateLock) {
1095                     if (!isOpen())
1096                         return 0;
1097                     readerThread = NativeThread.current();
1098                 }
1099                 n = Net.poll(fd, events, timeout);
1100             } finally {
1101                 readerThread = 0;
1102                 end(n > 0);
1103             }
1104             return n;
1105         }
1106     }
1107 
1108     /**
1109      * Translates an interest operation set into a native poll event set
1110      */
1111     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
1112         int newOps = 0;
1113 
1114         if ((ops & SelectionKey.OP_READ) != 0)
1115             newOps |= Net.POLLIN;
1116         if ((ops & SelectionKey.OP_WRITE) != 0)
1117             newOps |= Net.POLLOUT;
1118         if ((ops & SelectionKey.OP_CONNECT) != 0)
1119             newOps |= Net.POLLIN;
1120         sk.selector.putEventOps(sk, newOps);
1121     }
1122 
1123     public FileDescriptor getFD() {
1124         return fd;
1125     }
1126 
1127     public int getFDVal() {
1128         return fdVal;
1129     }
1130 
1131 
1132     // -- Native methods --
1133 
1134     private static native void initIDs();
1135 
1136     private static native void disconnect0(FileDescriptor fd, boolean isIPv6)
1137         throws IOException;
1138 
1139     private native int receive0(FileDescriptor fd, long address, int len,
1140                                 boolean connected)
1141         throws IOException;
1142 
1143     private native int send0(boolean preferIPv6, FileDescriptor fd, long address,
1144                              int len, InetAddress addr, int port)
1145         throws IOException;
1146 
1147     static {
1148         IOUtil.load();
1149         initIDs();
1150     }
1151 
1152 }