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