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