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