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