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