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