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