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