001/* VMChannel.java -- Native interface suppling channel operations. 002 Copyright (C) 2006 Free Software Foundation, Inc. 003 004The original of this file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037package gnu.java.nio; 038 039import gnu.classpath.Configuration; 040 041import java.io.IOException; 042import java.net.Inet4Address; 043import java.net.Inet6Address; 044import java.net.InetAddress; 045import java.net.InetSocketAddress; 046import java.net.SocketAddress; 047import java.net.SocketException; 048import java.nio.ByteBuffer; 049import java.nio.MappedByteBuffer; 050 051import org.jikesrvm.VM; 052import org.jikesrvm.mm.mminterface.MemoryManager; 053import org.jikesrvm.runtime.FileSystem; 054import org.vmmagic.pragma.NonMovingAllocation; 055 056 057/** 058 * Native interface to support configuring of channel to run in a non-blocking 059 * manner and support scatter/gather io operations. 060 * <p> 061 * JikesRVM-specific implementation by Robin Garner and Filip Pizlo. 062 * <p> 063 * Note: JavaDoc from GNU Classpath has been deleted on methods where it would 064 * cause JavaDoc warnings. 065 */ 066public final class VMChannel 067{ 068 /** 069 * Our reference implementation uses an integer to store the native 070 * file descriptor. 071 */ 072 private final State nfd; 073 074 private Kind kind; 075 076 public VMChannel() 077 { 078 // XXX consider adding security check here, so only Classpath 079 // code may create instances. 080 this.nfd = new State(); 081 kind = Kind.OTHER; 082 } 083 084 VMChannel(final int native_fd) throws IOException 085 { 086 this(); 087 this.nfd.setNativeFD(native_fd); 088 } 089 090 public State getState() 091 { 092 return nfd; 093 } 094 095 /** 096 * Don't do fast I/O for the standard file descriptors - these are used 097 * for throwing exceptions, so may not be able to allocate. 098 * 099 * Cache the max of the IDs to avoid gratuitous native calls. 100 */ 101 private static int MAX_STANDARD_FD; 102 103 private static int max(int[] values) { 104 int result = values[0]; 105 for (int i : values) 106 if (i > result) result = i; 107 return result; 108 } 109 110 static 111 { 112 // load the shared library needed for native methods. 113 if (Configuration.INIT_LOAD_LIBRARY) 114 { 115 System.loadLibrary ("javanio"); 116 } 117 initIDs(); 118 MAX_STANDARD_FD = max(new int[] {stdin_fd(),stdin_fd(),stderr_fd()}); 119 } 120 121 public static VMChannel getStdin() throws IOException 122 { 123 return new VMChannel(stdin_fd()); 124 } 125 126 public static VMChannel getStdout() throws IOException 127 { 128 return new VMChannel(stdout_fd()); 129 } 130 131 public static VMChannel getStderr() throws IOException 132 { 133 return new VMChannel(stderr_fd()); 134 } 135 136 private static native int stdin_fd(); 137 private static native int stdout_fd(); 138 private static native int stderr_fd(); 139 140 141 public void setBlocking(boolean blocking) throws IOException 142 { 143 setBlocking(nfd.getNativeFD(), blocking); 144 } 145 146 private static native void setBlocking(int fd, boolean blocking) 147 throws IOException; 148 149 public int available() throws IOException 150 { 151 return available(nfd.getNativeFD()); 152 } 153 154 private static native int available(int native_fd) throws IOException; 155 156 /** 157 * A thread-local store of non-moving buffers. Used to perform IO to 158 * in cases where the actual user buffer is in a moving space. 159 */ 160 private static class LocalByteArray extends ThreadLocal<byte[]> { 161 private static final int INITIAL_BUFFER_SIZE = 8192; 162 @Override 163 @NonMovingAllocation 164 protected byte[] initialValue() { 165 return new byte[INITIAL_BUFFER_SIZE]; 166 } 167 168 /** 169 * Get a buffer, ensuring it is at least 'len' in size 170 * @param len Minimum length of the buffer 171 * @return a new or recycled buffer 172 */ 173 @NonMovingAllocation 174 public byte[] get(int len) { 175 byte[] buf = get(); 176 if (buf.length < len) { 177 /* Allocate a new buffer by successive doubling of capacity */ 178 int newCapacity = buf.length << 1; 179 while (newCapacity < len) 180 newCapacity <<= 1; 181 buf = new byte[newCapacity]; 182 set(buf); 183 } 184 return buf; 185 } 186 } 187 188 /** 189 * Thread-local buffer for VM-side buffering of write calls 190 */ 191 private static final LocalByteArray localByteArray = new LocalByteArray() ; 192 193 /** 194 * Reads a byte buffer directly using the supplied file descriptor. 195 * 196 * @param dst Direct Byte Buffer to read to. 197 * @return Number of bytes read. 198 * @throws IOException If an error occurs or dst is not a direct buffers. 199 */ 200 public int read(ByteBuffer dst) throws IOException { 201 return read(dst,dst.position(),dst.limit()-dst.position()); 202 } 203 204 /* 205 * Read a byte buffer, given a starting position and length. 206 * Looks at the type of buffer and decides which is the fastest way 207 * to perform the write. If the buffer is backed by a byte array, use 208 * the internal method, otherwise push it out to classpath's native function 209 * (the slow way). 210 * 211 * @param dst 212 * @param pos 213 * @param len 214 * @return the number of bytes actually read 215 * @throws IOException 216 */ 217 private int read(ByteBuffer dst, int pos, int len) throws IOException { 218 int bytes; 219 if (len == 1) { 220 int b = FileSystem.readByte(nfd.getNativeFD()); 221 if (b >= 0) { 222 dst.put((byte)(b & 0xFF)); 223 dst.position(pos+1); 224 return 1; 225 } else 226 bytes = b; 227 } else if (dst.hasArray()) { 228 bytes = read(dst.array(),pos,len); 229 } else { 230 return read(nfd.getNativeFD(), dst); 231 } 232 if (bytes > 0) 233 dst.position(pos+bytes); 234 return bytes; 235 } 236 237 /** 238 * Reads a byte array directly. Performs optimal buffering. 239 * 240 * If the target buffer is pinned, use it directly. Otherwise 241 * allocate one of the thread-local buffers, perform the IO to 242 * that, and copy the result to the target array. 243 * 244 * @param dst Byte array to read to 245 * @param pos Starting offset in the buffer 246 * @param len Number of bytes to read 247 * @return Number of bytes read. 248 * @throws IOException If an error occurs or dst is not a direct buffers. 249 */ 250 private int read(byte[] dst, int pos, int len) throws IOException { 251 if (MemoryManager.willNeverMove(dst)) { 252 return read(nfd.getNativeFD(),dst,pos,len); 253 } else { 254 byte[] buffer; 255 // Rebuffer the IO in a thread-local byte array 256 buffer = localByteArray.get(len); 257 258 /* perform the read */ 259 int bytes = read(nfd.getNativeFD(),buffer,0,len); 260 if (bytes > 0) 261 System.arraycopy(buffer,0,dst,pos,bytes); 262 return bytes; 263 } 264 } 265 266 /** 267 * Use JikesRVM's internal read function - the fast way. 268 * 269 * @param fd File descriptor 270 * @param dst Destination buffer 271 * @param position Starting offset in the buffer 272 * @param len Number of bytes to read 273 * @return Number of bytes read, or -1 for end of file. 274 * @throws IOException when an error occurs during reading 275 */ 276 private static int read(int fd, byte[] dst, int position, int len) throws IOException { 277 if (VM.VerifyAssertions) VM._assert(MemoryManager.willNeverMove(dst)); 278 int bytes = FileSystem.readBytes(fd,dst,position,len); 279 if (bytes < 0) { 280 throw new IOException("Error code "+Integer.toString(bytes)); 281 } 282 if (bytes == 0) { 283 bytes = -1; 284 } 285 return bytes; 286 } 287 288 /** 289 * Classpath's native read method. Slow, due to the amount of JNI processing. 290 * 291 * @param fd the file descriptor of the file to read 292 * @param dst the buffer that the read bytes will be written to 293 * @return the number of bytes actually read 294 * @throws IOException when an error occurs during reading 295 */ 296 private static native int read(int fd, ByteBuffer dst) throws IOException; 297 298 public int read() throws IOException 299 { 300 //return read(nfd.getNativeFD()); 301 int result = FileSystem.readByte(nfd.getNativeFD()); 302 if (result < -1) { 303 throw new IOException("Error code "+Integer.toString(result)); 304 } 305 return result; 306 } 307 308 private static native int read(int fd) throws IOException; 309 310 /** 311 * Reads into byte buffers directly using the supplied file descriptor. 312 * Assumes that the buffer list contains DirectBuffers. Will perform a 313 * scattering read. 314 * 315 * @param dsts An array direct byte buffers. 316 * @param offset Index of the first buffer to read to. 317 * @param length The number of buffers to read to. 318 * @return Number of bytes read. 319 * @throws IOException If an error occurs or the dsts are not direct buffers. 320 */ 321 public long readScattering(ByteBuffer[] dsts, int offset, int length) 322 throws IOException 323 { 324 if (offset + length > dsts.length) 325 throw new IndexOutOfBoundsException("offset + length > dsts.length"); 326 327 return readScattering(nfd.getNativeFD(), dsts, offset, length); 328 } 329 330 private static native long readScattering(int fd, ByteBuffer[] dsts, 331 int offset, int length) 332 throws IOException; 333 334 public SocketAddress receive(ByteBuffer dst) throws IOException 335 { 336 if (kind != Kind.SOCK_DGRAM) 337 throw new SocketException("not a datagram socket"); 338 ByteBuffer hostPort = ByteBuffer.allocateDirect(18); 339 int hostlen = receive(nfd.getNativeFD(), dst, hostPort); 340 if (hostlen == 0) 341 return null; 342 if (hostlen == 4) // IPv4 343 { 344 byte[] addr = new byte[4]; 345 hostPort.get(addr); 346 int port = hostPort.getShort() & 0xFFFF; 347 return new InetSocketAddress(Inet4Address.getByAddress(addr), port); 348 } 349 if (hostlen == 16) // IPv6 350 { 351 byte[] addr = new byte[16]; 352 hostPort.get(addr); 353 int port = hostPort.getShort() & 0xFFFF; 354 return new InetSocketAddress(Inet6Address.getByAddress(addr), port); 355 } 356 357 throw new SocketException("host address received with invalid length: " 358 + hostlen); 359 } 360 361 private static native int receive (int fd, ByteBuffer dst, ByteBuffer address) 362 throws IOException; 363 364 /** 365 * Writes from a byte array using the supplied file descriptor. 366 * 367 * @param src The source buffer. 368 * @param pos Starting offset in the buffer 369 * @param len Number of bytes to write 370 * @return Number of bytes written. 371 * @throws IOException when an error occurs during writing 372 */ 373 public int write(byte[] src, int pos, int len) throws IOException { 374 if (MemoryManager.willNeverMove(src)) { 375 return write(nfd.getNativeFD(), src, pos, len); 376 } else { 377 byte[] buffer; 378 // Rebuffer the IO in a thread-local DirectBuffer 379 buffer = localByteArray.get(len); 380 if (VM.VerifyAssertions) VM._assert(MemoryManager.willNeverMove(buffer)); 381 System.arraycopy(src, pos, buffer,0,len); 382 return write(nfd.getNativeFD(),buffer,0,len); 383 } 384 } 385 386 public int write(ByteBuffer src, int pos, int len) throws IOException { 387 int bytes; 388 if (len == 1) { 389 int ok = FileSystem.writeByte(nfd.getNativeFD(),src.get(pos)); 390 if(ok == 0){ 391 bytes = 1; 392 }else{ 393 throw new IOException("Error code " + Integer.toString(ok)); 394 } 395 } else if (src.hasArray()) { 396 bytes = write(src.array(),pos,len); 397 } else { 398 // Use classpath version, which does buffer housekeeping 399 return write(nfd.getNativeFD(), src); 400 } 401 if (bytes > 0) 402 src.position(src.position()+bytes); 403 return bytes; 404 } 405 406 public int write(ByteBuffer src) throws IOException { 407 if (nfd.getNativeFD() > MAX_STANDARD_FD) 408 return write(src,src.position(),src.limit()-src.position()); 409 else 410 return write(nfd.getNativeFD(),src); 411 } 412 413 /** 414 * Use JikesRVM's internal read function - the fast way. 415 * 416 * @param fd File descriptor 417 * @param src Source buffer 418 * @param pos Starting offset in the buffer 419 * @param len Number of bytes to write 420 * @return Number of bytes written. 421 * @throws IOException when an error occurs during writing 422 */ 423 private static int write(int fd, byte[] src, int pos, int len) throws IOException { 424 int bytes = FileSystem.writeBytes(fd,src,pos,len); 425 if (bytes < 0) 426 throw new IOException("Error code "+Integer.toString(bytes)); 427 return bytes; 428 } 429 430 /** 431 * Classpath's native write method. Slow, due to the amount of JNI processing. 432 * 433 * @param fd the file's descriptor 434 * @param src the source buffer for the bytes that will be written 435 * @return Number of bytes written 436 * @throws IOException when an error occurs during writing 437 */ 438 private static native int write(int fd, ByteBuffer src) throws IOException; 439 440 public long writeGathering(ByteBuffer[] srcs, int offset, int length) 441 throws IOException 442 { 443 if (offset + length > srcs.length) 444 throw new IndexOutOfBoundsException("offset + length > srcs.length"); 445 446 // A gathering write is limited to 16 buffers; when writing, ensure 447 // that we have at least one buffer with something in it in the 16 448 // buffer window starting at offset. 449 while (!srcs[offset].hasRemaining() && offset < srcs.length) 450 offset++; 451 452 // There are no buffers with anything to write. 453 if (offset == srcs.length) 454 return 0; 455 456 // If we advanced `offset' so far that we don't have `length' 457 // buffers left, reset length to only the remaining buffers. 458 if (length > srcs.length - offset) 459 length = srcs.length - offset; 460 461 return writeGathering(nfd.getNativeFD(), srcs, offset, length); 462 } 463 464 private native long writeGathering(int fd, ByteBuffer[] srcs, 465 int offset, int length) 466 throws IOException; 467 468 public int send(ByteBuffer src, InetSocketAddress dst) 469 throws IOException 470 { 471 InetAddress addr = dst.getAddress(); 472 if (addr == null) 473 throw new NullPointerException(); 474 if (addr instanceof Inet4Address) 475 return send(nfd.getNativeFD(), src, addr.getAddress(), dst.getPort()); 476 else if (addr instanceof Inet6Address) 477 return send6(nfd.getNativeFD(), src, addr.getAddress(), dst.getPort()); 478 else 479 throw new SocketException("unrecognized inet address type"); 480 } 481 482 // Send to an IPv4 address. 483 private static native int send(int fd, ByteBuffer src, byte[] addr, int port) 484 throws IOException; 485 486 // Send to an IPv6 address. 487 private static native int send6(int fd, ByteBuffer src, byte[] addr, int port) 488 throws IOException; 489 490 public void write(int b) throws IOException 491 { 492 //write(nfd.getNativeFD(), b); 493 int result = FileSystem.writeByte(nfd.getNativeFD(), b); 494 if (result < 0) { 495 throw new IOException("Error code "+Integer.toString(result)); 496 } 497 } 498 499 private static native void write(int fd, int b) throws IOException; 500 501 private native static void initIDs(); 502 503 // Network (socket) specific methods. 504 505 /** 506 * Create a new socket. This method will initialize the native file 507 * descriptor state of this instance. 508 * 509 * @param stream Whether or not to create a streaming socket, or a datagram 510 * socket. 511 * @throws IOException If creating a new socket fails, or if this 512 * channel already has its native descriptor initialized. 513 */ 514 public void initSocket(boolean stream) throws IOException 515 { 516 if (nfd.isValid()) 517 throw new IOException("native FD already initialized"); 518 if (stream) 519 kind = Kind.SOCK_STREAM; 520 else 521 kind = Kind.SOCK_DGRAM; 522 nfd.setNativeFD(socket(stream)); 523 } 524 525 /** 526 * Create a new socket, returning the native file descriptor. 527 * 528 * @param stream Set to true for streaming sockets; false for datagrams. 529 * @return The native file descriptor. 530 * @throws IOException If creating the socket fails. 531 */ 532 private static native int socket(boolean stream) throws IOException; 533 534 /** 535 * Connect the underlying socket file descriptor to the remote host. 536 * 537 * @param saddr The address to connect to. 538 * @param timeout The connect timeout to use for blocking connects. 539 * @return True if the connection succeeded; false if the file descriptor 540 * is in non-blocking mode and the connection did not immediately 541 * succeed. 542 * @throws SocketException If an error occurs while connecting. 543 */ 544 public boolean connect(InetSocketAddress saddr, int timeout) 545 throws SocketException 546 { 547 int fd; 548 549 InetAddress addr = saddr.getAddress(); 550 551 // Translates an IOException into a SocketException to conform 552 // to the throws clause. 553 try 554 { 555 fd = nfd.getNativeFD(); 556 } 557 catch (IOException ioe) 558 { 559 throw new SocketException(ioe.getMessage()); 560 } 561 562 if (addr instanceof Inet4Address) 563 return connect(fd, addr.getAddress(), saddr.getPort(), 564 timeout); 565 if (addr instanceof Inet6Address) 566 return connect6(fd, addr.getAddress(), saddr.getPort(), 567 timeout); 568 throw new SocketException("unsupported internet address"); 569 } 570 571 private static native boolean connect(int fd, byte[] addr, int port, int timeout) 572 throws SocketException; 573 574 private static native boolean connect6(int fd, byte[] addr, int port, int timeout) 575 throws SocketException; 576 577 /** 578 * Disconnect this channel, if it is a datagram socket. Disconnecting 579 * a datagram channel will disassociate it from any address, so the 580 * socket will remain open, but can send and receive datagrams from 581 * any address. 582 * 583 * @throws IOException If disconnecting this channel fails, or if this 584 * channel is not a datagram channel. 585 */ 586 public void disconnect() throws IOException 587 { 588 if (kind != Kind.SOCK_DGRAM) 589 throw new IOException("can only disconnect datagram channels"); 590 disconnect(nfd.getNativeFD()); 591 } 592 593 private static native void disconnect(int fd) throws IOException; 594 595 public InetSocketAddress getLocalAddress() throws IOException 596 { 597 if (!nfd.isValid()) 598 return null; 599 ByteBuffer name = ByteBuffer.allocateDirect(18); 600 int namelen = getsockname(nfd.getNativeFD(), name); 601 if (namelen == 0) // not bound 602 return null; // XXX return some wildcard? 603 if (namelen == 4) 604 { 605 byte[] addr = new byte[4]; 606 name.get(addr); 607 int port = name.getShort() & 0xFFFF; 608 return new InetSocketAddress(Inet4Address.getByAddress(addr), port); 609 } 610 if (namelen == 16) 611 { 612 byte[] addr = new byte[16]; 613 name.get(addr); 614 int port = name.getShort() & 0xFFFF; 615 return new InetSocketAddress(Inet6Address.getByAddress(addr), port); 616 } 617 throw new SocketException("invalid address length"); 618 } 619 620 private static native int getsockname(int fd, ByteBuffer name) 621 throws IOException; 622 623 public InetSocketAddress getPeerAddress() throws IOException 624 { 625 if (!nfd.isValid()) 626 return null; 627 ByteBuffer name = ByteBuffer.allocateDirect(18); 628 int namelen = getpeername (nfd.getNativeFD(), name); 629 if (namelen == 0) // not connected yet 630 return null; 631 if (namelen == 4) // IPv4 632 { 633 byte[] addr = new byte[4]; 634 name.get(addr); 635 int port = name.getShort() & 0xFFFF; 636 return new InetSocketAddress(Inet4Address.getByAddress(addr), port); 637 } 638 else if (namelen == 16) // IPv6 639 { 640 byte[] addr = new byte[16]; 641 name.get(addr); 642 int port = name.getShort() & 0xFFFF; 643 return new InetSocketAddress(Inet6Address.getByAddress(addr), port); 644 } 645 throw new SocketException("invalid address length"); 646 } 647 648 /* 649 * The format here is the peer address, followed by the port number. 650 * The returned value is the length of the peer address; thus, there 651 * will be LEN + 2 valid bytes put into NAME. 652 */ 653 private static native int getpeername(int fd, ByteBuffer name) 654 throws IOException; 655 656 /** 657 * Accept an incoming connection, returning a new VMChannel, or null 658 * if the channel is nonblocking and no connection is pending. 659 * 660 * @return The accepted connection, or null. 661 * @throws IOException If an IO error occurs. 662 */ 663 public VMChannel accept() throws IOException 664 { 665 int new_fd = accept(nfd.getNativeFD()); 666 if (new_fd == -1) // non-blocking accept had no pending connection 667 return null; 668 return new VMChannel(new_fd); 669 } 670 671 private static native int accept(int native_fd) throws IOException; 672 673 // File-specific methods. 674 675 public void openFile(String path, int mode) throws IOException 676 { 677 if (nfd.isValid() || nfd.isClosed()) 678 throw new IOException("can't reinitialize this channel"); 679 int fd = open(path, mode); 680 nfd.setNativeFD(fd); 681 kind = Kind.FILE; 682 } 683 684 private static native int open(String path, int mode) throws IOException; 685 686 public long position() throws IOException 687 { 688 if (kind != Kind.FILE) 689 throw new IOException("not a file"); 690 return position(nfd.getNativeFD()); 691 } 692 693 private static native long position(int fd) throws IOException; 694 695 public void seek(long pos) throws IOException 696 { 697 if (kind != Kind.FILE) 698 throw new IOException("not a file"); 699 seek(nfd.getNativeFD(), pos); 700 } 701 702 private static native void seek(int fd, long pos) throws IOException; 703 704 public void truncate(long length) throws IOException 705 { 706 if (kind != Kind.FILE) 707 throw new IOException("not a file"); 708 truncate(nfd.getNativeFD(), length); 709 } 710 711 private static native void truncate(int fd, long len) throws IOException; 712 713 public boolean lock(long pos, long len, boolean shared, boolean wait) 714 throws IOException 715 { 716 if (kind != Kind.FILE) 717 throw new IOException("not a file"); 718 return lock(nfd.getNativeFD(), pos, len, shared, wait); 719 } 720 721 private static native boolean lock(int fd, long pos, long len, 722 boolean shared, boolean wait) 723 throws IOException; 724 725 public void unlock(long pos, long len) throws IOException 726 { 727 if (kind != Kind.FILE) 728 throw new IOException("not a file"); 729 unlock(nfd.getNativeFD(), pos, len); 730 } 731 732 private static native void unlock(int fd, long pos, long len) throws IOException; 733 734 public long size() throws IOException 735 { 736 if (kind != Kind.FILE) 737 throw new IOException("not a file"); 738 return size(nfd.getNativeFD()); 739 } 740 741 private static native long size(int fd) throws IOException; 742 743 public MappedByteBuffer map(char mode, long position, int size) 744 throws IOException 745 { 746 if (kind != Kind.FILE) 747 throw new IOException("not a file"); 748 return map(nfd.getNativeFD(), mode, position, size); 749 } 750 751 private static native MappedByteBuffer map(int fd, char mode, 752 long position, int size) 753 throws IOException; 754 755 public boolean flush(boolean metadata) throws IOException 756 { 757 if (kind != Kind.FILE) 758 throw new IOException("not a file"); 759 return flush(nfd.getNativeFD(), metadata); 760 } 761 762 private static native boolean flush(int fd, boolean metadata) throws IOException; 763 764 // Close. 765 766 /** 767 * Close this socket. The socket is also automatically closed when this 768 * object is finalized. 769 * 770 * @throws IOException If closing the socket fails, or if this object has 771 * no open socket. 772 */ 773 public void close() throws IOException 774 { 775 nfd.close(); 776 } 777 778 static native void close(int native_fd) throws IOException; 779 780 /** 781 * <p>Provides a simple mean for the JNI code to find out whether the 782 * current thread was interrupted by a call to Thread.interrupt().</p> 783 * 784 * @return true if the current thread was interrupted, false otherwise 785 */ 786 static boolean isThreadInterrupted() 787 { 788 return Thread.currentThread().isInterrupted(); 789 } 790 791 // Inner classes. 792 793 /** 794 * A wrapper for a native file descriptor integer. This tracks the state 795 * of an open file descriptor, and ensures that 796 * 797 * This class need not be fully supported by virtual machines; if a 798 * virtual machine does not use integer file descriptors, or does and 799 * wishes to hide that, then the methods of this class may be stubbed out. 800 * 801 * System-specific classes that depend on access to native file descriptor 802 * integers SHOULD declare this fact. 803 */ 804 public final class State 805 { 806 private int native_fd; 807 private boolean valid; 808 private boolean closed; 809 810 State() 811 { 812 native_fd = -1; 813 valid = false; 814 closed = false; 815 } 816 817 public boolean isValid() 818 { 819 return valid; 820 } 821 822 public boolean isClosed() 823 { 824 return closed; 825 } 826 827 public int getNativeFD() throws IOException 828 { 829 if (!valid) 830 throw new IOException("invalid file descriptor"); 831 return native_fd; 832 } 833 834 void setNativeFD(final int native_fd) throws IOException 835 { 836 if (valid) 837 throw new IOException("file descriptor already initialized"); 838 this.native_fd = native_fd; 839 valid = true; 840 } 841 842 public void close() throws IOException 843 { 844 if (!valid) 845 throw new IOException("invalid file descriptor"); 846 try 847 { 848 VMChannel.close(native_fd); 849 } 850 finally 851 { 852 valid = false; 853 closed = true; 854 } 855 } 856 857 @Override 858 public String toString() 859 { 860 if (closed) 861 return "<<closed>>"; 862 if (!valid) 863 return "<<invalid>>"; 864 return String.valueOf(native_fd); 865 } 866 867 @Override 868 protected void finalize() throws Throwable 869 { 870 try 871 { 872 if (valid) 873 close(); 874 } 875 finally 876 { 877 super.finalize(); 878 } 879 } 880 } 881 882 /** 883 * An enumeration of possible kinds of channel. 884 */ 885 static class Kind // XXX enum 886 { 887 /** A streaming (TCP) socket. */ 888 static final Kind SOCK_STREAM = new Kind(); 889 890 /** A datagram (UDP) socket. */ 891 static final Kind SOCK_DGRAM = new Kind(); 892 893 /** A file. */ 894 static final Kind FILE = new Kind(); 895 896 /** Something else; not a socket or file. */ 897 static final Kind OTHER = new Kind(); 898 899 private Kind() { } 900 } 901}