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