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