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