1 /* 2 * Copyright (c) 2001, 2011, 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 == StandardSocketOption.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 == StandardSocketOption.IP_MULTICAST_TTL || 200 name == StandardSocketOption.IP_MULTICAST_LOOP) 201 { 202 // options are protocol dependent 203 Net.setSocketOption(fd, family, name, value); 204 return this; 205 } 206 207 if (name == StandardSocketOption.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 == StandardSocketOption.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 == StandardSocketOption.IP_MULTICAST_TTL || 256 name == StandardSocketOption.IP_MULTICAST_LOOP) 257 { 258 return (T) Net.getSocketOption(fd, family, name); 259 } 260 261 if (name == StandardSocketOption.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(StandardSocketOption.SO_SNDBUF); 295 set.add(StandardSocketOption.SO_RCVBUF); 296 set.add(StandardSocketOption.SO_REUSEADDR); 297 set.add(StandardSocketOption.SO_BROADCAST); 298 set.add(StandardSocketOption.IP_TOS); 299 set.add(StandardSocketOption.IP_MULTICAST_IF); 300 set.add(StandardSocketOption.IP_MULTICAST_TTL); 301 set.add(StandardSocketOption.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 = null; 392 try { 393 bb = Util.getTemporaryDirectBuffer(newSize); 394 int n = receiveIntoNativeBuffer(fd, bb, newSize, 0); 395 bb.flip(); 396 if (n > 0 && rem > 0) 397 dst.put(bb); 398 return n; 399 } finally { 400 Util.releaseTemporaryDirectBuffer(bb); 401 } 402 } 403 404 private int receiveIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb, 405 int rem, int pos) 406 throws IOException 407 { 408 int n = receive0(fd, ((DirectBuffer)bb).address() + pos, rem, 409 isConnected()); 410 if (n > 0) 411 bb.position(pos + n); 412 return n; 413 } 414 415 public int send(ByteBuffer src, SocketAddress target) 416 throws IOException 417 { 418 if (src == null) 419 throw new NullPointerException(); 420 421 synchronized (writeLock) { 422 ensureOpen(); 423 InetSocketAddress isa = (InetSocketAddress)target; 424 InetAddress ia = isa.getAddress(); 425 if (ia == null) 426 throw new IOException("Target address not resolved"); 427 synchronized (stateLock) { 428 if (!isConnected()) { 429 if (target == null) 430 throw new NullPointerException(); 431 SecurityManager sm = System.getSecurityManager(); 432 if (sm != null) { 433 if (ia.isMulticastAddress()) { 434 sm.checkMulticast(isa.getAddress()); 435 } else { 436 sm.checkConnect(isa.getAddress().getHostAddress(), 437 isa.getPort()); 438 } 439 } 440 } else { // Connected case; Check address then write 441 if (!target.equals(remoteAddress)) { 442 throw new IllegalArgumentException( 443 "Connected address not equal to target address"); 444 } 445 return write(src); 446 } 447 } 448 449 int n = 0; 450 try { 451 begin(); 452 if (!isOpen()) 453 return 0; 454 writerThread = NativeThread.current(); 455 do { 456 n = send(fd, src, target); 457 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 458 459 synchronized (stateLock) { 460 if (isOpen() && (localAddress == null)) { 461 localAddress = Net.localAddress(fd); 462 } 463 } 464 return IOStatus.normalize(n); 465 } finally { 466 writerThread = 0; 467 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 468 assert IOStatus.check(n); 469 } 470 } 471 } 472 473 private int send(FileDescriptor fd, ByteBuffer src, SocketAddress target) 474 throws IOException 475 { 476 if (src instanceof DirectBuffer) 477 return sendFromNativeBuffer(fd, src, target); 478 479 // Substitute a native buffer 480 int pos = src.position(); 481 int lim = src.limit(); 482 assert (pos <= lim); 483 int rem = (pos <= lim ? lim - pos : 0); 484 485 ByteBuffer bb = null; 486 try { 487 bb = Util.getTemporaryDirectBuffer(rem); 488 bb.put(src); 489 bb.flip(); 490 // Do not update src until we see how many bytes were written 491 src.position(pos); 492 493 int n = sendFromNativeBuffer(fd, bb, target); 494 if (n > 0) { 495 // now update src 496 src.position(pos + n); 497 } 498 return n; 499 } finally { 500 Util.releaseTemporaryDirectBuffer(bb); 501 } 502 } 503 504 private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb, 505 SocketAddress target) 506 throws IOException 507 { 508 int pos = bb.position(); 509 int lim = bb.limit(); 510 assert (pos <= lim); 511 int rem = (pos <= lim ? lim - pos : 0); 512 513 boolean preferIPv6 = (family != StandardProtocolFamily.INET); 514 int written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos, 515 rem, target); 516 if (written > 0) 517 bb.position(pos + written); 518 return written; 519 } 520 521 public int read(ByteBuffer buf) throws IOException { 522 if (buf == null) 523 throw new NullPointerException(); 524 synchronized (readLock) { 525 synchronized (stateLock) { 526 ensureOpen(); 527 if (!isConnected()) 528 throw new NotYetConnectedException(); 529 } 530 int n = 0; 531 try { 532 begin(); 533 if (!isOpen()) 534 return 0; 535 readerThread = NativeThread.current(); 536 do { 537 n = IOUtil.read(fd, buf, -1, nd, readLock); 538 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 539 return IOStatus.normalize(n); 540 } finally { 541 readerThread = 0; 542 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 543 assert IOStatus.check(n); 544 } 545 } 546 } 547 548 public long read(ByteBuffer[] dsts, int offset, int length) 549 throws IOException 550 { 551 if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) 552 throw new IndexOutOfBoundsException(); 553 synchronized (readLock) { 554 synchronized (stateLock) { 555 ensureOpen(); 556 if (!isConnected()) 557 throw new NotYetConnectedException(); 558 } 559 long n = 0; 560 try { 561 begin(); 562 if (!isOpen()) 563 return 0; 564 readerThread = NativeThread.current(); 565 do { 566 n = IOUtil.read(fd, dsts, offset, length, nd); 567 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 568 return IOStatus.normalize(n); 569 } finally { 570 readerThread = 0; 571 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 572 assert IOStatus.check(n); 573 } 574 } 575 } 576 577 public int write(ByteBuffer buf) throws IOException { 578 if (buf == null) 579 throw new NullPointerException(); 580 synchronized (writeLock) { 581 synchronized (stateLock) { 582 ensureOpen(); 583 if (!isConnected()) 584 throw new NotYetConnectedException(); 585 } 586 int n = 0; 587 try { 588 begin(); 589 if (!isOpen()) 590 return 0; 591 writerThread = NativeThread.current(); 592 do { 593 n = IOUtil.write(fd, buf, -1, nd, writeLock); 594 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 595 return IOStatus.normalize(n); 596 } finally { 597 writerThread = 0; 598 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 599 assert IOStatus.check(n); 600 } 601 } 602 } 603 604 public long write(ByteBuffer[] srcs, int offset, int length) 605 throws IOException 606 { 607 if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) 608 throw new IndexOutOfBoundsException(); 609 synchronized (writeLock) { 610 synchronized (stateLock) { 611 ensureOpen(); 612 if (!isConnected()) 613 throw new NotYetConnectedException(); 614 } 615 long n = 0; 616 try { 617 begin(); 618 if (!isOpen()) 619 return 0; 620 writerThread = NativeThread.current(); 621 do { 622 n = IOUtil.write(fd, srcs, offset, length, nd); 623 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 624 return IOStatus.normalize(n); 625 } finally { 626 writerThread = 0; 627 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 628 assert IOStatus.check(n); 629 } 630 } 631 } 632 633 protected void implConfigureBlocking(boolean block) throws IOException { 634 IOUtil.configureBlocking(fd, block); 635 } 636 637 public SocketAddress localAddress() { 638 synchronized (stateLock) { 639 return localAddress; 640 } 641 } 642 643 public SocketAddress remoteAddress() { 644 synchronized (stateLock) { 645 return remoteAddress; 646 } 647 } 648 649 @Override 650 public DatagramChannel bind(SocketAddress local) throws IOException { 651 synchronized (readLock) { 652 synchronized (writeLock) { 653 synchronized (stateLock) { 654 ensureOpen(); 655 if (localAddress != null) 656 throw new AlreadyBoundException(); 657 InetSocketAddress isa; 658 if (local == null) { 659 isa = new InetSocketAddress(0); 660 } else { 661 isa = Net.checkAddress(local); 662 663 // only Inet4Address allowed with IPv4 socket 664 if (family == StandardProtocolFamily.INET) { 665 InetAddress addr = isa.getAddress(); 666 if (!(addr instanceof Inet4Address)) 667 throw new UnsupportedAddressTypeException(); 668 } 669 } 670 SecurityManager sm = System.getSecurityManager(); 671 if (sm != null) { 672 sm.checkListen(isa.getPort()); 673 } 674 Net.bind(family, fd, isa.getAddress(), isa.getPort()); 675 localAddress = Net.localAddress(fd); 676 } 677 } 678 } 679 return this; 680 } 681 682 public boolean isConnected() { 683 synchronized (stateLock) { 684 return (state == ST_CONNECTED); 685 } 686 } 687 688 void ensureOpenAndUnconnected() throws IOException { // package-private 689 synchronized (stateLock) { 690 if (!isOpen()) 691 throw new ClosedChannelException(); 692 if (state != ST_UNCONNECTED) 693 throw new IllegalStateException("Connect already invoked"); 694 } 695 } 696 697 public DatagramChannel connect(SocketAddress sa) throws IOException { 698 int localPort = 0; 699 700 synchronized(readLock) { 701 synchronized(writeLock) { 702 synchronized (stateLock) { 703 ensureOpenAndUnconnected(); 704 InetSocketAddress isa = Net.checkAddress(sa); 705 SecurityManager sm = System.getSecurityManager(); 706 if (sm != null) 707 sm.checkConnect(isa.getAddress().getHostAddress(), 708 isa.getPort()); 709 int n = Net.connect(family, 710 fd, 711 isa.getAddress(), 712 isa.getPort()); 713 if (n <= 0) 714 throw new Error(); // Can't happen 715 716 // Connection succeeded; disallow further invocation 717 state = ST_CONNECTED; 718 remoteAddress = sa; 719 sender = isa; 720 cachedSenderInetAddress = isa.getAddress(); 721 cachedSenderPort = isa.getPort(); 722 723 // set or refresh local address 724 localAddress = Net.localAddress(fd); 725 } 726 } 727 } 728 return this; 729 } 730 731 public DatagramChannel disconnect() throws IOException { 732 synchronized(readLock) { 733 synchronized(writeLock) { 734 synchronized (stateLock) { 735 if (!isConnected() || !isOpen()) 736 return this; 737 InetSocketAddress isa = (InetSocketAddress)remoteAddress; 738 SecurityManager sm = System.getSecurityManager(); 739 if (sm != null) 740 sm.checkConnect(isa.getAddress().getHostAddress(), 741 isa.getPort()); 742 disconnect0(fd); 743 remoteAddress = null; 744 state = ST_UNCONNECTED; 745 746 // refresh local address 747 localAddress = Net.localAddress(fd); 748 } 749 } 750 } 751 return this; 752 } 753 754 /** 755 * Joins channel's socket to the given group/interface and 756 * optional source address. 757 */ 758 private MembershipKey innerJoin(InetAddress group, 759 NetworkInterface interf, 760 InetAddress source) 761 throws IOException 762 { 763 if (!group.isMulticastAddress()) 764 throw new IllegalArgumentException("Group not a multicast address"); 765 766 // check multicast address is compatible with this socket 767 if (group instanceof Inet4Address) { 768 if (family == StandardProtocolFamily.INET6 && !Net.canIPv6SocketJoinIPv4Group()) 769 throw new IllegalArgumentException("Group is not IPv4 multicast address"); 770 } else if (group instanceof Inet6Address) { 771 if (family != StandardProtocolFamily.INET6) 772 throw new IllegalArgumentException("Group is not IPv6 multicast address"); 773 } else { 774 throw new IllegalArgumentException("Address type not supported"); 775 } 776 777 // check source address 778 if (source != null) { 779 if (source.isAnyLocalAddress()) 780 throw new IllegalArgumentException("Source address is a wildcard address"); 781 if (source.isMulticastAddress()) 782 throw new IllegalArgumentException("Source address is multicast address"); 783 if (source.getClass() != group.getClass()) 784 throw new IllegalArgumentException("Source address is different type to group"); 785 } 786 787 SecurityManager sm = System.getSecurityManager(); 788 if (sm != null) 789 sm.checkMulticast(group); 790 791 synchronized (stateLock) { 792 if (!isOpen()) 793 throw new ClosedChannelException(); 794 795 // check the registry to see if we are already a member of the group 796 if (registry == null) { 797 registry = new MembershipRegistry(); 798 } else { 799 // return existing membership key 800 MembershipKey key = registry.checkMembership(group, interf, source); 801 if (key != null) 802 return key; 803 } 804 805 MembershipKeyImpl key; 806 if ((family == StandardProtocolFamily.INET6) && 807 ((group instanceof Inet6Address) || Net.canJoin6WithIPv4Group())) 808 { 809 int index = interf.getIndex(); 810 if (index == -1) 811 throw new IOException("Network interface cannot be identified"); 812 813 // need multicast and source address as byte arrays 814 byte[] groupAddress = Net.inet6AsByteArray(group); 815 byte[] sourceAddress = (source == null) ? null : 816 Net.inet6AsByteArray(source); 817 818 // join the group 819 int n = Net.join6(fd, groupAddress, index, sourceAddress); 820 if (n == IOStatus.UNAVAILABLE) 821 throw new UnsupportedOperationException(); 822 823 key = new MembershipKeyImpl.Type6(this, group, interf, source, 824 groupAddress, index, sourceAddress); 825 826 } else { 827 // need IPv4 address to identify interface 828 Inet4Address target = Net.anyInet4Address(interf); 829 if (target == null) 830 throw new IOException("Network interface not configured for IPv4"); 831 832 int groupAddress = Net.inet4AsInt(group); 833 int targetAddress = Net.inet4AsInt(target); 834 int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source); 835 836 // join the group 837 int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress); 838 if (n == IOStatus.UNAVAILABLE) 839 throw new UnsupportedOperationException(); 840 841 key = new MembershipKeyImpl.Type4(this, group, interf, source, 842 groupAddress, targetAddress, sourceAddress); 843 } 844 845 registry.add(key); 846 return key; 847 } 848 } 849 850 @Override 851 public MembershipKey join(InetAddress group, 852 NetworkInterface interf) 853 throws IOException 854 { 855 return innerJoin(group, interf, null); 856 } 857 858 @Override 859 public MembershipKey join(InetAddress group, 860 NetworkInterface interf, 861 InetAddress source) 862 throws IOException 863 { 864 if (source == null) 865 throw new NullPointerException("source address is null"); 866 return innerJoin(group, interf, source); 867 } 868 869 // package-private 870 void drop(MembershipKeyImpl key) { 871 assert key.channel() == this; 872 873 synchronized (stateLock) { 874 if (!key.isValid()) 875 return; 876 877 try { 878 if (key instanceof MembershipKeyImpl.Type6) { 879 MembershipKeyImpl.Type6 key6 = 880 (MembershipKeyImpl.Type6)key; 881 Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source()); 882 } else { 883 MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4)key; 884 Net.drop4(fd, key4.groupAddress(), key4.interfaceAddress(), 885 key4.source()); 886 } 887 } catch (IOException ioe) { 888 // should not happen 889 throw new AssertionError(ioe); 890 } 891 892 key.invalidate(); 893 registry.remove(key); 894 } 895 } 896 897 /** 898 * Block datagrams from given source if a memory to receive all 899 * datagrams. 900 */ 901 void block(MembershipKeyImpl key, InetAddress source) 902 throws IOException 903 { 904 assert key.channel() == this; 905 assert key.sourceAddress() == null; 906 907 synchronized (stateLock) { 908 if (!key.isValid()) 909 throw new IllegalStateException("key is no longer valid"); 910 if (source.isAnyLocalAddress()) 911 throw new IllegalArgumentException("Source address is a wildcard address"); 912 if (source.isMulticastAddress()) 913 throw new IllegalArgumentException("Source address is multicast address"); 914 if (source.getClass() != key.group().getClass()) 915 throw new IllegalArgumentException("Source address is different type to group"); 916 917 int n; 918 if (key instanceof MembershipKeyImpl.Type6) { 919 MembershipKeyImpl.Type6 key6 = 920 (MembershipKeyImpl.Type6)key; 921 n = Net.block6(fd, key6.groupAddress(), key6.index(), 922 Net.inet6AsByteArray(source)); 923 } else { 924 MembershipKeyImpl.Type4 key4 = 925 (MembershipKeyImpl.Type4)key; 926 n = Net.block4(fd, key4.groupAddress(), key4.interfaceAddress(), 927 Net.inet4AsInt(source)); 928 } 929 if (n == IOStatus.UNAVAILABLE) { 930 // ancient kernel 931 throw new UnsupportedOperationException(); 932 } 933 } 934 } 935 936 /** 937 * Unblock given source. 938 */ 939 void unblock(MembershipKeyImpl key, InetAddress source) { 940 assert key.channel() == this; 941 assert key.sourceAddress() == null; 942 943 synchronized (stateLock) { 944 if (!key.isValid()) 945 throw new IllegalStateException("key is no longer valid"); 946 947 try { 948 if (key instanceof MembershipKeyImpl.Type6) { 949 MembershipKeyImpl.Type6 key6 = 950 (MembershipKeyImpl.Type6)key; 951 Net.unblock6(fd, key6.groupAddress(), key6.index(), 952 Net.inet6AsByteArray(source)); 953 } else { 954 MembershipKeyImpl.Type4 key4 = 955 (MembershipKeyImpl.Type4)key; 956 Net.unblock4(fd, key4.groupAddress(), key4.interfaceAddress(), 957 Net.inet4AsInt(source)); 958 } 959 } catch (IOException ioe) { 960 // should not happen 961 throw new AssertionError(ioe); 962 } 963 } 964 } 965 966 protected void implCloseSelectableChannel() throws IOException { 967 synchronized (stateLock) { 968 nd.preClose(fd); 969 ResourceManager.afterUdpClose(); 970 971 // if member of mulitcast group then invalidate all keys 972 if (registry != null) 973 registry.invalidateAll(); 974 975 long th; 976 if ((th = readerThread) != 0) 977 NativeThread.signal(th); 978 if ((th = writerThread) != 0) 979 NativeThread.signal(th); 980 if (!isRegistered()) 981 kill(); 982 } 983 } 984 985 public void kill() throws IOException { 986 synchronized (stateLock) { 987 if (state == ST_KILLED) 988 return; 989 if (state == ST_UNINITIALIZED) { 990 state = ST_KILLED; 991 return; 992 } 993 assert !isOpen() && !isRegistered(); 994 nd.close(fd); 995 state = ST_KILLED; 996 } 997 } 998 999 protected void finalize() throws IOException { 1000 // fd is null if constructor threw exception 1001 if (fd != null) 1002 close(); 1003 } 1004 1005 /** 1006 * Translates native poll revent set into a ready operation set 1007 */ 1008 public boolean translateReadyOps(int ops, int initialOps, 1009 SelectionKeyImpl sk) { 1010 int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes 1011 int oldOps = sk.nioReadyOps(); 1012 int newOps = initialOps; 1013 1014 if ((ops & PollArrayWrapper.POLLNVAL) != 0) { 1015 // This should only happen if this channel is pre-closed while a 1016 // selection operation is in progress 1017 // ## Throw an error if this channel has not been pre-closed 1018 return false; 1019 } 1020 1021 if ((ops & (PollArrayWrapper.POLLERR 1022 | PollArrayWrapper.POLLHUP)) != 0) { 1023 newOps = intOps; 1024 sk.nioReadyOps(newOps); 1025 return (newOps & ~oldOps) != 0; 1026 } 1027 1028 if (((ops & PollArrayWrapper.POLLIN) != 0) && 1029 ((intOps & SelectionKey.OP_READ) != 0)) 1030 newOps |= SelectionKey.OP_READ; 1031 1032 if (((ops & PollArrayWrapper.POLLOUT) != 0) && 1033 ((intOps & SelectionKey.OP_WRITE) != 0)) 1034 newOps |= SelectionKey.OP_WRITE; 1035 1036 sk.nioReadyOps(newOps); 1037 return (newOps & ~oldOps) != 0; 1038 } 1039 1040 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) { 1041 return translateReadyOps(ops, sk.nioReadyOps(), sk); 1042 } 1043 1044 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) { 1045 return translateReadyOps(ops, 0, sk); 1046 } 1047 1048 /** 1049 * Translates an interest operation set into a native poll event set 1050 */ 1051 public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) { 1052 int newOps = 0; 1053 1054 if ((ops & SelectionKey.OP_READ) != 0) 1055 newOps |= PollArrayWrapper.POLLIN; 1056 if ((ops & SelectionKey.OP_WRITE) != 0) 1057 newOps |= PollArrayWrapper.POLLOUT; 1058 if ((ops & SelectionKey.OP_CONNECT) != 0) 1059 newOps |= PollArrayWrapper.POLLIN; 1060 sk.selector.putEventOps(sk, newOps); 1061 } 1062 1063 public FileDescriptor getFD() { 1064 return fd; 1065 } 1066 1067 public int getFDVal() { 1068 return fdVal; 1069 } 1070 1071 1072 // -- Native methods -- 1073 1074 private static native void initIDs(); 1075 1076 private static native void disconnect0(FileDescriptor fd) 1077 throws IOException; 1078 1079 private native int receive0(FileDescriptor fd, long address, int len, 1080 boolean connected) 1081 throws IOException; 1082 1083 private native int send0(boolean preferIPv6, FileDescriptor fd, long address, int len, 1084 SocketAddress sa) 1085 throws IOException; 1086 1087 static { 1088 Util.load(); 1089 initIDs(); 1090 } 1091 1092 }