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