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