? gnu/java/nio/FileChannelImpl.java ? gnu/java/nio/KqueueSelectionKeyImpl.java ? gnu/java/nio/KqueueSelectorImpl.java ? gnu/java/nio/NIOSocketImpl.java ? gnu/java/nio/VMChannelOwner.java ? gnu/java/nio/channels/SelectorProviderImpl.java ? gnu/java/nio/channels/SocketChannelImpl.java ? native/jni/java-net/netif.c ? native/jni/java-net/netif.h ? native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c ? native/jni/java-nio/javanio.c ? native/jni/java-nio/javanio.h Index: configure.ac =================================================================== RCS file: /cvsroot/classpath/classpath/configure.ac,v retrieving revision 1.182 diff -u -r1.182 configure.ac --- configure.ac 8 Sep 2006 08:59:57 -0000 1.182 +++ configure.ac 15 Sep 2006 00:48:12 -0000 @@ -356,7 +356,8 @@ crt_externs.h \ fcntl.h \ sys/mman.h \ - magic.h]) + magic.h \ + sys/event.h]) AC_EGREP_HEADER(uint32_t, stdint.h, AC_DEFINE(HAVE_INT32_DEFINED, 1, [Define to 1 if you have uint32_t])) AC_EGREP_HEADER(uint32_t, inttypes.h, AC_DEFINE(HAVE_INT32_DEFINED, 1, [Define to 1 if you have uint32_t])) @@ -365,7 +366,7 @@ AC_CHECK_FUNCS([ftruncate fsync select \ gethostname socket strerror fork pipe execve open close \ - lseek fstat read write htonl memset htons connect \ + lseek fstat read readv write writev htonl memset htons connect \ getsockname getpeername bind listen accept \ recvfrom send sendto setsockopt getsockopt time mktime \ gethostbyname_r localtime_r \ @@ -373,13 +374,20 @@ fcntl \ mmap munmap mincore msync madvise getpagesize sysconf \ lstat readlink \ - inet_aton inet_addr inet_pton \ - ]) + inet_aton inet_addr inet_pton \ + getifaddrs kqueue kevent]) LIBMAGIC= AC_CHECK_LIB(magic, magic_open, LIBMAGIC=-lmagic) AC_SUBST(LIBMAGIC) + AC_MSG_CHECKING([whether struct sockaddr_in6 is in netinet/in.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct sockaddr_in6 addr6;]])], + [AC_DEFINE(HAVE_INET6, 1, + [Define if inet6 structures are defined in netinet/in.h.]) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)]) + AC_HEADER_TIME AC_STRUCT_TM AC_STRUCT_TIMEZONE Index: gnu/java/nio/channels/FileChannelImpl.java =================================================================== RCS file: gnu/java/nio/channels/FileChannelImpl.java diff -N gnu/java/nio/channels/FileChannelImpl.java --- gnu/java/nio/channels/FileChannelImpl.java 14 May 2006 03:34:55 -0000 1.22 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,553 +0,0 @@ -/* FileChannelImpl.java -- - Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package gnu.java.nio.channels; - -import gnu.classpath.Configuration; -import gnu.java.nio.FileLockImpl; -import gnu.java.nio.VMChannel; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.nio.channels.NonReadableChannelException; -import java.nio.channels.NonWritableChannelException; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; - -/** - * This file is not user visible ! - * But alas, Java does not have a concept of friendly packages - * so this class is public. - * Instances of this class are created by invoking getChannel - * Upon a Input/Output/RandomAccessFile object. - */ -public final class FileChannelImpl extends FileChannel -{ - // These are mode values for open(). - public static final int READ = 1; - public static final int WRITE = 2; - public static final int APPEND = 4; - - // EXCL is used only when making a temp file. - public static final int EXCL = 8; - public static final int SYNC = 16; - public static final int DSYNC = 32; - - public static FileChannelImpl in; - public static FileChannelImpl out; - public static FileChannelImpl err; - - private static native void init(); - - static - { - if (Configuration.INIT_LOAD_LIBRARY) - { - System.loadLibrary("javanio"); - } - - init(); - - in = new FileChannelImpl(0, READ); - out = new FileChannelImpl(1, WRITE); - err = new FileChannelImpl(2, WRITE); - } - - /** - * This is the actual native file descriptor value - */ - // System's notion of file descriptor. It might seem redundant to - // initialize this given that it is reassigned in the constructors. - // However, this is necessary because if open() throws an exception - // we want to make sure this has the value -1. This is the most - // efficient way to accomplish that. - private int fd = -1; - private VMChannel ch; - - private int mode; - - final String description; - - /* Open a file. MODE is a combination of the above mode flags. */ - /* This is a static factory method, so that VM implementors can decide - * substitute subclasses of FileChannelImpl. */ - public static FileChannelImpl create(File file, int mode) - throws FileNotFoundException - { - return new FileChannelImpl(file, mode); - } - - private FileChannelImpl(File file, int mode) - throws FileNotFoundException - { - String path = file.getPath(); - description = path; - fd = open (path, mode); - this.mode = mode; - this.ch = VMChannel.getVMChannel(this); - - // First open the file and then check if it is a a directory - // to avoid race condition. - if (file.isDirectory()) - { - try - { - close(); - } - catch (IOException e) - { - /* ignore it */ - } - - throw new FileNotFoundException(description + " is a directory"); - } - } - - /** - * Constructor for default channels in, out and err. - * - * Used by init() (native code). - * - * @param fd the file descriptor (0, 1, 2 for stdin, stdout, stderr). - * - * @param mode READ or WRITE - */ - FileChannelImpl (int fd, int mode) - { - this.fd = fd; - this.mode = mode; - this.description = "descriptor(" + fd + ")"; - this.ch = VMChannel.getVMChannel(this); - } - - private native int open (String path, int mode) throws FileNotFoundException; - - public native int available () throws IOException; - private native long implPosition () throws IOException; - private native void seek (long newPosition) throws IOException; - private native void implTruncate (long size) throws IOException; - - public native void unlock (long pos, long len) throws IOException; - - public native long size () throws IOException; - - protected native void implCloseChannel() throws IOException; - - /** - * Makes sure the Channel is properly closed. - */ - protected void finalize() throws IOException - { - if (fd != -1) - close(); - } - - public int read (ByteBuffer dst) throws IOException - { - /* - int result; - byte[] buffer = new byte [dst.remaining ()]; - - result = read (buffer, 0, buffer.length); - - if (result > 0) - dst.put (buffer, 0, result); - - return result; - */ - return ch.read(dst); - } - - public int read (ByteBuffer dst, long position) - throws IOException - { - if (position < 0) - throw new IllegalArgumentException ("position: " + position); - long oldPosition = implPosition (); - position (position); - int result = read(dst); - position (oldPosition); - - return result; - } - - public native int read () - throws IOException; - - public native int read (byte[] buffer, int offset, int length) - throws IOException; - - public long read (ByteBuffer[] dsts, int offset, int length) - throws IOException - { - return ch.readScattering(dsts, offset, length); - } - - public int write (ByteBuffer src) throws IOException - { - return ch.write(src); - } - - public int write (ByteBuffer src, long position) - throws IOException - { - if (position < 0) - throw new IllegalArgumentException ("position: " + position); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & WRITE) == 0) - throw new NonWritableChannelException (); - - int result; - long oldPosition; - - oldPosition = implPosition (); - seek (position); - result = write(src); - seek (oldPosition); - - return result; - } - - public native void write (byte[] buffer, int offset, int length) - throws IOException; - - public native void write (int b) throws IOException; - - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - return ch.writeGathering(srcs, offset, length); - } - - public native MappedByteBuffer mapImpl (char mode, long position, int size) - throws IOException; - - public MappedByteBuffer map (FileChannel.MapMode mode, - long position, long size) - throws IOException - { - char nmode = 0; - if (mode == MapMode.READ_ONLY) - { - nmode = 'r'; - if ((this.mode & READ) == 0) - throw new NonReadableChannelException(); - } - else if (mode == MapMode.READ_WRITE || mode == MapMode.PRIVATE) - { - nmode = mode == MapMode.READ_WRITE ? '+' : 'c'; - if ((this.mode & WRITE) != WRITE) - throw new NonWritableChannelException(); - if ((this.mode & READ) != READ) - throw new NonReadableChannelException(); - } - else - throw new IllegalArgumentException ("mode: " + mode); - - if (position < 0 || size < 0 || size > Integer.MAX_VALUE) - throw new IllegalArgumentException ("position: " + position - + ", size: " + size); - return mapImpl(nmode, position, (int) size); - } - - /** - * msync with the disk - */ - public void force (boolean metaData) throws IOException - { - if (!isOpen ()) - throw new ClosedChannelException (); - - force (); - } - - private native void force (); - - // like transferTo, but with a count of less than 2Gbytes - private int smallTransferTo (long position, int count, - WritableByteChannel target) - throws IOException - { - ByteBuffer buffer; - try - { - // Try to use a mapped buffer if we can. If this fails for - // any reason we'll fall back to using a ByteBuffer. - buffer = map (MapMode.READ_ONLY, position, count); - } - catch (IOException e) - { - buffer = ByteBuffer.allocate (count); - read (buffer, position); - buffer.flip(); - } - - return target.write (buffer); - } - - public long transferTo (long position, long count, - WritableByteChannel target) - throws IOException - { - if (position < 0 - || count < 0) - throw new IllegalArgumentException ("position: " + position - + ", count: " + count); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & READ) == 0) - throw new NonReadableChannelException (); - - final int pageSize = 65536; - long total = 0; - - while (count > 0) - { - int transferred - = smallTransferTo (position, (int)Math.min (count, pageSize), - target); - if (transferred < 0) - break; - total += transferred; - position += transferred; - count -= transferred; - } - - return total; - } - - // like transferFrom, but with a count of less than 2Gbytes - private int smallTransferFrom (ReadableByteChannel src, long position, - int count) - throws IOException - { - ByteBuffer buffer = null; - - if (src instanceof FileChannel) - { - try - { - // Try to use a mapped buffer if we can. If this fails - // for any reason we'll fall back to using a ByteBuffer. - buffer = ((FileChannel)src).map (MapMode.READ_ONLY, position, - count); - } - catch (IOException e) - { - } - } - - if (buffer == null) - { - buffer = ByteBuffer.allocate ((int) count); - src.read (buffer); - buffer.flip(); - } - - return write (buffer, position); - } - - public long transferFrom (ReadableByteChannel src, long position, - long count) - throws IOException - { - if (position < 0 - || count < 0) - throw new IllegalArgumentException ("position: " + position - + ", count: " + count); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & WRITE) == 0) - throw new NonWritableChannelException (); - - final int pageSize = 65536; - long total = 0; - - while (count > 0) - { - int transferred = smallTransferFrom (src, position, - (int)Math.min (count, pageSize)); - if (transferred < 0) - break; - total += transferred; - position += transferred; - count -= transferred; - } - - return total; - } - - // Shared sanity checks between lock and tryLock methods. - private void lockCheck(long position, long size, boolean shared) - throws IOException - { - if (position < 0 - || size < 0) - throw new IllegalArgumentException ("position: " + position - + ", size: " + size); - - if (!isOpen ()) - throw new ClosedChannelException(); - - if (shared && ((mode & READ) == 0)) - throw new NonReadableChannelException(); - - if (!shared && ((mode & WRITE) == 0)) - throw new NonWritableChannelException(); - } - - public FileLock tryLock (long position, long size, boolean shared) - throws IOException - { - lockCheck(position, size, shared); - - boolean completed = false; - try - { - begin(); - boolean lockable = lock(position, size, shared, false); - completed = true; - return (lockable - ? new FileLockImpl(this, position, size, shared) - : null); - } - finally - { - end(completed); - } - } - - /** Try to acquire a lock at the given position and size. - * On success return true. - * If wait as specified, block until we can get it. - * Otherwise return false. - */ - private native boolean lock(long position, long size, - boolean shared, boolean wait) throws IOException; - - public FileLock lock (long position, long size, boolean shared) - throws IOException - { - lockCheck(position, size, shared); - - boolean completed = false; - try - { - boolean lockable = lock(position, size, shared, true); - completed = true; - return (lockable - ? new FileLockImpl(this, position, size, shared) - : null); - } - finally - { - end(completed); - } - } - - public long position () - throws IOException - { - if (!isOpen ()) - throw new ClosedChannelException (); - - return implPosition (); - } - - public FileChannel position (long newPosition) - throws IOException - { - if (newPosition < 0) - throw new IllegalArgumentException ("newPosition: " + newPosition); - - if (!isOpen ()) - throw new ClosedChannelException (); - - // FIXME note semantics if seeking beyond eof. - // We should seek lazily - only on a write. - seek (newPosition); - return this; - } - - public FileChannel truncate (long size) - throws IOException - { - if (size < 0) - throw new IllegalArgumentException ("size: " + size); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & WRITE) == 0) - throw new NonWritableChannelException (); - - if (size < size ()) - implTruncate (size); - - return this; - } - - public String toString() - { - return (this.getClass() - + "[fd=" + fd - + ",mode=" + mode + "," - + description + "]"); - } - - /** - * @return The native file descriptor. - */ - public int getNativeFD() - { - return fd; - } -} Index: include/Makefile.am =================================================================== RCS file: /cvsroot/classpath/classpath/include/Makefile.am,v retrieving revision 1.69 diff -u -r1.69 Makefile.am --- include/Makefile.am 17 Jul 2006 18:37:19 -0000 1.69 +++ include/Makefile.am 15 Sep 2006 00:48:12 -0000 @@ -128,10 +128,11 @@ $(top_srcdir)/include/gnu_java_net_VMPlainDatagramSocketImpl.h \ $(top_srcdir)/include/gnu_java_net_VMPlainSocketImpl.h \ $(top_srcdir)/include/gnu_java_net_local_LocalSocketImpl.h \ +$(top_srcdir)/include/gnu_java_nio_FileChannelImpl.h \ +$(top_srcdir)/include/gnu_java_nio_KqueueSelectorImpl.h \ $(top_srcdir)/include/gnu_java_nio_VMChannel.h \ $(top_srcdir)/include/gnu_java_nio_VMPipe.h \ $(top_srcdir)/include/gnu_java_nio_VMSelector.h \ -$(top_srcdir)/include/gnu_java_nio_channels_FileChannelImpl.h \ $(top_srcdir)/include/gnu_java_nio_charset_iconv_IconvEncoder.h \ $(top_srcdir)/include/gnu_java_nio_charset_iconv_IconvDecoder.h \ $(top_srcdir)/include/java_io_VMFile.h \ @@ -214,12 +215,18 @@ $(JAVAH) -o $@ java.net.VMNetworkInterface $(top_srcdir)/include/java_net_VMURLConnection.h: $(top_srcdir)/vm/reference/java/net/VMURLConnection.java $(JAVAH) -o $@ java.net.VMURLConnection + $(top_srcdir)/include/java_nio_VMDirectByteBuffer.h: $(top_srcdir)/vm/reference/java/nio/VMDirectByteBuffer.java $(JAVAH) -o $@ java.nio.VMDirectByteBuffer $(top_srcdir)/include/java_nio_MappedByteBufferImpl.h: $(top_srcdir)/java/nio/MappedByteBufferImpl.java $(JAVAH) -o $@ java.nio.MappedByteBufferImpl -$(top_srcdir)/include/gnu_java_nio_channels_FileChannelImpl.h: $(top_srcdir)/gnu/java/nio/channels/FileChannelImpl.java - $(JAVAH) -o $@ gnu.java.nio.channels.FileChannelImpl + +$(top_srcdir)/include/gnu_java_nio_FileChannelImpl.h: $(top_srcdir)/gnu/java/nio/FileChannelImpl.java + $(JAVAH) -o $@ gnu.java.nio.FileChannelImpl + +$(top_srcdir)/include/gnu_java_nio_KqueueSelectorImpl.h: $(top_srcdir)/gnu/java/nio/KqueueSelectorImpl.java + $(JAVAH) -o $@ gnu.java.nio.KqueueSelectorImpl + $(top_srcdir)/include/gnu_java_nio_charset_iconv_IconvDecoder.h: $(top_srcdir)/gnu/java/nio/charset/iconv/IconvDecoder.java $(JAVAH) -o $@ gnu.java.nio.charset.iconv.IconvDecoder $(top_srcdir)/include/gnu_java_nio_charset_iconv_IconvEncoder.h: $(top_srcdir)/gnu/java/nio/charset/iconv/IconvEncoder.java Index: java/io/FileDescriptor.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/io/FileDescriptor.java,v retrieving revision 1.26 diff -u -r1.26 FileDescriptor.java --- java/io/FileDescriptor.java 15 Aug 2006 11:37:05 -0000 1.26 +++ java/io/FileDescriptor.java 15 Sep 2006 00:48:12 -0000 @@ -39,7 +39,7 @@ package java.io; -import gnu.java.nio.channels.FileChannelImpl; +import gnu.java.nio.FileChannelImpl; import java.nio.channels.ByteChannel; import java.nio.channels.FileChannel; Index: java/io/FileInputStream.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/io/FileInputStream.java,v retrieving revision 1.34 diff -u -r1.34 FileInputStream.java --- java/io/FileInputStream.java 2 Jul 2005 20:32:37 -0000 1.34 +++ java/io/FileInputStream.java 15 Sep 2006 00:48:12 -0000 @@ -38,8 +38,9 @@ package java.io; -import gnu.java.nio.channels.FileChannelImpl; +import gnu.java.nio.FileChannelImpl; +import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 @@ -107,7 +108,20 @@ if (s != null) s.checkRead(file.getPath()); - ch = FileChannelImpl.create(file, FileChannelImpl.READ); + try + { + ch = FileChannelImpl.create(file, FileChannelImpl.READ); + } + catch (FileNotFoundException fnfe) + { + throw fnfe; + } + catch (IOException ioe) + { + FileNotFoundException fnfe = new FileNotFoundException(file.getPath()); + fnfe.initCause(ioe); + throw fnfe; + } } /** @@ -266,7 +280,7 @@ || offset + len > buf.length) throw new ArrayIndexOutOfBoundsException(); - return ch.read(buf, offset, len); + return ch.read(ByteBuffer.wrap(buf, offset, len)); } /** Index: java/io/FileOutputStream.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/io/FileOutputStream.java,v retrieving revision 1.37 diff -u -r1.37 FileOutputStream.java --- java/io/FileOutputStream.java 2 Jul 2005 20:32:37 -0000 1.37 +++ java/io/FileOutputStream.java 15 Sep 2006 00:48:12 -0000 @@ -38,8 +38,9 @@ package java.io; -import gnu.java.nio.channels.FileChannelImpl; +import gnu.java.nio.FileChannelImpl; +import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 @@ -155,10 +156,23 @@ if (s != null) s.checkWrite(file.getPath()); - ch = FileChannelImpl.create(file, (append - ? FileChannelImpl.WRITE - | FileChannelImpl.APPEND - : FileChannelImpl.WRITE)); + try + { + ch = FileChannelImpl.create(file, (append + ? FileChannelImpl.WRITE + | FileChannelImpl.APPEND + : FileChannelImpl.WRITE)); + } + catch (FileNotFoundException fnfe) + { + throw fnfe; + } + catch (IOException ioe) + { + FileNotFoundException fnfe = new FileNotFoundException(file.getPath()); + fnfe.initCause(ioe); + throw fnfe; + } } /** @@ -266,7 +280,7 @@ || offset + len > buf.length) throw new ArrayIndexOutOfBoundsException (); - ch.write (buf, offset, len); + ch.write(ByteBuffer.wrap(buf, offset, len)); } /** Index: java/io/RandomAccessFile.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/io/RandomAccessFile.java,v retrieving revision 1.48 diff -u -r1.48 RandomAccessFile.java --- java/io/RandomAccessFile.java 7 Dec 2005 15:27:05 -0000 1.48 +++ java/io/RandomAccessFile.java 15 Sep 2006 00:48:13 -0000 @@ -38,7 +38,7 @@ package java.io; -import gnu.java.nio.channels.FileChannelImpl; +import gnu.java.nio.FileChannelImpl; import java.nio.channels.FileChannel; @@ -122,7 +122,20 @@ s.checkWrite(fileName); } - ch = FileChannelImpl.create(file, fdmode); + try + { + ch = FileChannelImpl.create(file, fdmode); + } + catch (FileNotFoundException fnfe) + { + throw fnfe; + } + catch (IOException ioe) + { + FileNotFoundException fnfe = new FileNotFoundException(file.getPath()); + fnfe.initCause(ioe); + throw fnfe; + } fd = new FileDescriptor(ch); if ((fdmode & FileChannelImpl.WRITE) != 0) out = new DataOutputStream (new FileOutputStream (fd)); Index: java/net/DatagramSocket.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/net/DatagramSocket.java,v retrieving revision 1.48 diff -u -r1.48 DatagramSocket.java --- java/net/DatagramSocket.java 16 Dec 2005 17:13:54 -0000 1.48 +++ java/net/DatagramSocket.java 15 Sep 2006 00:48:13 -0000 @@ -180,7 +180,18 @@ if (factory != null) impl = factory.createDatagramSocketImpl(); else - impl = new PlainDatagramSocketImpl(); + { + try + { + impl = new PlainDatagramSocketImpl(); + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } } else try @@ -194,7 +205,16 @@ { System.err.println("Could not instantiate class: java.net." + propVal + "DatagramSocketImpl"); - impl = new PlainDatagramSocketImpl(); + try + { + impl = new PlainDatagramSocketImpl(); + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } } if (address != null) @@ -578,7 +598,13 @@ && ! ((DatagramChannelImpl) getChannel()).isInChannelOperation()) throw new IllegalBlockingModeException(); - getImpl().receive(p); + DatagramPacket p2 = new DatagramPacket(p.getData(), p.getOffset(), p.maxlen); + getImpl().receive(p2); + p.length = p2.length; + if (p2.getAddress() != null) + p.setAddress(p2.getAddress()); + if (p2.getPort() != -1) + p.setPort(p2.getPort()); SecurityManager s = System.getSecurityManager(); if (s != null && isConnected()) @@ -649,6 +675,9 @@ { if (isClosed()) throw new SocketException("socket is closed"); + + if (address == null) + address = new InetSocketAddress(InetAddress.ANY_IF, 0); if (! (address instanceof InetSocketAddress)) throw new IllegalArgumentException("unsupported address type"); Index: java/net/NetworkInterface.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/net/NetworkInterface.java,v retrieving revision 1.19 diff -u -r1.19 NetworkInterface.java --- java/net/NetworkInterface.java 12 Sep 2006 14:55:33 -0000 1.19 +++ java/net/NetworkInterface.java 15 Sep 2006 00:48:13 -0000 @@ -38,6 +38,8 @@ package java.net; +import gnu.classpath.SystemProperties; + import java.util.Collection; import java.util.Collections; import java.util.Enumeration; @@ -58,25 +60,13 @@ */ public final class NetworkInterface { - private String name; - private Vector inetAddresses; - - NetworkInterface(String name, InetAddress address) - { - this.name = name; - this.inetAddresses = new Vector(1, 1); - this.inetAddresses.add(address); - } + private final VMNetworkInterface netif; - NetworkInterface(String name, InetAddress[] addresses) + private NetworkInterface(VMNetworkInterface netif) { - this.name = name; - this.inetAddresses = new Vector(addresses.length, 1); - - for (int i = 0; i < addresses.length; i++) - this.inetAddresses.add(addresses[i]); + this.netif = netif; } - + /** * Returns the name of the network interface * @@ -84,7 +74,7 @@ */ public String getName() { - return name; + return netif.name; } /** @@ -100,6 +90,7 @@ public Enumeration getInetAddresses() { SecurityManager s = System.getSecurityManager(); + Vector inetAddresses = new Vector(netif.addresses); if (s == null) return inetAddresses.elements(); @@ -131,7 +122,7 @@ */ public String getDisplayName() { - return name; + return netif.name; } /** @@ -148,15 +139,14 @@ public static NetworkInterface getByName(String name) throws SocketException { - for (Enumeration e = getNetworkInterfaces(); e.hasMoreElements();) + if (name == null) + throw new NullPointerException(); + VMNetworkInterface[] netifs = VMNetworkInterface.getVMInterfaces(); + for (int i = 0; i < netifs.length; i++) { - NetworkInterface tmp = (NetworkInterface) e.nextElement(); - - if (name.equals(tmp.getName())) - return tmp; + if (netifs[i].name.equals(name)) + return new NetworkInterface(netifs[i]); } - - // No interface with the given name found. return null; } @@ -173,55 +163,15 @@ public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketException { - for (Enumeration interfaces = getNetworkInterfaces(); - interfaces.hasMoreElements();) + if (addr == null) + throw new NullPointerException(); + VMNetworkInterface[] netifs = VMNetworkInterface.getVMInterfaces(); + for (int i = 0; i < netifs.length; i++) { - NetworkInterface tmp = (NetworkInterface) interfaces.nextElement(); - - for (Enumeration addresses = tmp.inetAddresses.elements(); - addresses.hasMoreElements();) - { - if (addr.equals((InetAddress) addresses.nextElement())) - return tmp; - } + if (netifs[i].addresses.contains(addr)) + return new NetworkInterface(netifs[i]); } - - throw new SocketException("no network interface is bound to such an IP address"); - } - - static private Collection condense(Collection interfaces) - { - final Map condensed = new HashMap(); - - final Iterator interfs = interfaces.iterator(); - while (interfs.hasNext()) { - - final NetworkInterface face = (NetworkInterface) interfs.next(); - final String name = face.getName(); - - if (condensed.containsKey(name)) - { - final NetworkInterface conface = (NetworkInterface) condensed.get(name); - if (!conface.inetAddresses.containsAll(face.inetAddresses)) - { - final Iterator faceAddresses = face.inetAddresses.iterator(); - while (faceAddresses.hasNext()) - { - final InetAddress faceAddress = (InetAddress) faceAddresses.next(); - if (!conface.inetAddresses.contains(faceAddress)) - { - conface.inetAddresses.add(faceAddress); - } - } - } - } - else - { - condensed.put(name, face); - } - } - - return condensed.values(); + return null; } /** @@ -233,14 +183,14 @@ */ public static Enumeration getNetworkInterfaces() throws SocketException { - Vector networkInterfaces = VMNetworkInterface.getInterfaces(); - - if (networkInterfaces.isEmpty()) - return null; - - Collection condensed = condense(networkInterfaces); - - return Collections.enumeration(condensed); + VMNetworkInterface[] netifs = VMNetworkInterface.getVMInterfaces(); + Vector networkInterfaces = new Vector(netifs.length); + for (int i = 0; i < netifs.length; i++) + { + if (!netifs[i].addresses.isEmpty()) + networkInterfaces.add(new NetworkInterface(netifs[i])); + } + return networkInterfaces.elements(); } /** @@ -257,7 +207,8 @@ NetworkInterface tmp = (NetworkInterface) obj; - return (name.equals(tmp.name) && inetAddresses.equals(tmp.inetAddresses)); + return (netif.name.equals(tmp.netif.name) + && (netif.addresses.equals(tmp.netif.addresses))); } /** @@ -268,7 +219,7 @@ public int hashCode() { // FIXME: hash correctly - return name.hashCode() + inetAddresses.hashCode(); + return netif.name.hashCode() + netif.addresses.hashCode(); } /** @@ -279,19 +230,22 @@ public String toString() { // FIXME: check if this is correct - String result; - String separator = System.getProperty("line.separator"); + StringBuffer result; + String separator = SystemProperties.getProperty("line.separator"); - result = - "name: " + getDisplayName() + " (" + getName() + ") addresses:" - + separator; + result = new StringBuffer(); + + result.append("name: "); + result.append(getDisplayName()); + result.append(" (").append(getName()).append(") addresses:"); + result.append(separator); - for (Enumeration e = inetAddresses.elements(); e.hasMoreElements();) + for (Iterator it = netif.addresses.iterator(); it.hasNext(); ) { - InetAddress address = (InetAddress) e.nextElement(); - result += address.toString() + ";" + separator; + InetAddress address = (InetAddress) it.next(); + result.append(address.toString()).append(";").append(separator); } - return result; + return result.toString(); } } Index: java/net/ServerSocket.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/net/ServerSocket.java,v retrieving revision 1.45 diff -u -r1.45 ServerSocket.java --- java/net/ServerSocket.java 10 Sep 2006 21:16:39 -0000 1.45 +++ java/net/ServerSocket.java 15 Sep 2006 00:48:13 -0000 @@ -39,6 +39,7 @@ package java.net; import gnu.java.net.PlainSocketImpl; +import gnu.java.nio.VMChannel; import java.io.IOException; import java.nio.channels.IllegalBlockingModeException; @@ -93,6 +94,7 @@ this.impl = impl; this.impl.create(true); + setReuseAddress(true); } /* @@ -381,10 +383,6 @@ return; impl.close(); - impl = null; - - if (getChannel() != null) - getChannel().close(); } /** @@ -424,7 +422,10 @@ */ public boolean isClosed() { - return impl == null; + VMChannel vmchannel = ((PlainSocketImpl) impl).getVMChannel(); + if (vmchannel == null) // Not created yet. + return false; + return vmchannel.getState().isClosed(); } /** Index: java/net/Socket.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/net/Socket.java,v retrieving revision 1.56 diff -u -r1.56 Socket.java --- java/net/Socket.java 10 Sep 2006 21:16:40 -0000 1.56 +++ java/net/Socket.java 15 Sep 2006 00:48:14 -0000 @@ -39,6 +39,7 @@ package java.net; import gnu.java.net.PlainSocketImpl; +import gnu.java.nio.VMChannel; import java.io.IOException; import java.io.InputStream; @@ -458,16 +459,22 @@ InetAddress addr = null; - try - { - addr = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR); - } - catch (SocketException e) - { - // (hopefully) shouldn't happen - // throw new java.lang.InternalError - // ("Error in PlainSocketImpl.getOption"); - return null; + if (impl instanceof PlainSocketImpl) + addr = ((PlainSocketImpl) impl).getLocalAddress().getAddress(); + + if (addr == null) + { + try + { + addr = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR); + } + catch (SocketException e) + { + // (hopefully) shouldn't happen + // throw new java.lang.InternalError + // ("Error in PlainSocketImpl.getOption"); + return null; + } } // FIXME: According to libgcj, checkConnect() is supposed to be called @@ -980,12 +987,8 @@ if (isClosed()) return; - getImpl().close(); + impl.close(); impl = null; - bound = false; - - if (getChannel() != null) - getChannel().close(); } /** @@ -998,16 +1001,17 @@ try { if (isConnected()) - return ("Socket[addr=" + getImpl().getInetAddress() + ",port=" - + getImpl().getPort() + ",localport=" - + getImpl().getLocalPort() + "]"); + return (super.toString() + + " [addr=" + getImpl().getInetAddress() + ",port=" + + getImpl().getPort() + ",localport=" + + getImpl().getLocalPort() + "]"); } catch (SocketException e) { // This cannot happen as we are connected. } - return "Socket[unconnected]"; + return super.toString() + " [unconnected]"; } /** @@ -1185,17 +1189,10 @@ */ public boolean isConnected() { - try - { - if (getImpl() == null) - return false; + if (impl == null) + return false; - return getImpl().getInetAddress() != null; - } - catch (SocketException e) - { - return false; - } + return impl.getInetAddress() != null; } /** @@ -1207,6 +1204,13 @@ */ public boolean isBound() { + if (isClosed()) + return false; + if (impl instanceof PlainSocketImpl) + { + InetSocketAddress addr = ((PlainSocketImpl) impl).getLocalAddress(); + return addr != null && addr.getAddress() != null; + } return bound; } @@ -1219,7 +1223,17 @@ */ public boolean isClosed() { - return impl == null; + if (impl == null) + return true; + if (impl instanceof PlainSocketImpl) + { + VMChannel vmchannel = ((PlainSocketImpl) impl).getVMChannel(); + if (vmchannel == null) + return false; // Not created yet. + VMChannel.State state = vmchannel.getState(); + return state.isClosed(); + } + return false; } /** Index: gnu/java/net/PlainDatagramSocketImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/net/PlainDatagramSocketImpl.java,v retrieving revision 1.10 diff -u -r1.10 PlainDatagramSocketImpl.java --- gnu/java/net/PlainDatagramSocketImpl.java 4 Jan 2006 20:50:20 -0000 1.10 +++ gnu/java/net/PlainDatagramSocketImpl.java 15 Sep 2006 00:48:14 -0000 @@ -38,13 +38,18 @@ package gnu.java.net; +import gnu.java.nio.VMChannel; + import java.io.IOException; +import java.lang.reflect.Field; import java.net.DatagramPacket; import java.net.DatagramSocketImpl; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketAddress; import java.net.SocketException; +import java.nio.ByteBuffer; /** * Written using on-line Java Platform 1.2 API Specification, as well @@ -62,11 +67,13 @@ */ public final class PlainDatagramSocketImpl extends DatagramSocketImpl { - + + private final VMChannel channel; + /** - * This is the actual underlying file descriptor + * The platform-specific socket implementation. */ - int native_fd = -1; + private final VMPlainSocketImpl impl; /** * Lock object to serialize threads wanting to receive @@ -81,25 +88,26 @@ /** * Default do nothing constructor */ - public PlainDatagramSocketImpl() + public PlainDatagramSocketImpl() throws IOException { - // Nothing to do here. + channel = new VMChannel(); + impl = new VMPlainSocketImpl(channel); } - protected void finalize() throws Throwable + /*protected void finalize() throws Throwable { synchronized (this) { - if (native_fd != -1) + if (channel.getState().isValid()) close(); } super.finalize(); - } + }*/ - public int getNativeFD() + /*public int getNativeFD() { return native_fd; - } + }*/ /** * Binds this socket to a particular port and interface @@ -109,20 +117,46 @@ * * @exception SocketException If an error occurs */ - protected synchronized void bind(int port, InetAddress addr) + protected synchronized void bind(int port, InetAddress addr) throws SocketException - { - VMPlainDatagramSocketImpl.bind(this, port, addr); - } + { + try + { + impl.bind(new InetSocketAddress(addr, port)); + } + catch (SocketException se) + { + throw se; + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } /** * Creates a new datagram socket * * @exception SocketException If an error occurs */ - protected synchronized void create() throws SocketException + protected synchronized void create() throws SocketException { - VMPlainDatagramSocketImpl.create(this); + try + { + channel.initSocket(false); + } + catch (SocketException se) + { + throw se; + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } } /** @@ -147,8 +181,14 @@ { synchronized (this) { - if (native_fd != -1) - close(); + try + { + if (channel.getState().isValid()) + channel.disconnect(); + } + catch (IOException ioe) + { + } } } @@ -181,6 +221,23 @@ return ((Integer) obj).intValue(); } + protected int getLocalPort() + { + if (channel == null) + return -1; + + try + { + InetSocketAddress local = channel.getLocalAddress(); + if (local == null) + return -1; + return local.getPort(); + } + catch (IOException ioe) + { + return -1; + } + } /** * Sends a packet of data to a remote host @@ -191,13 +248,19 @@ */ protected void send(DatagramPacket packet) throws IOException { - if (native_fd != -1) + synchronized (SEND_LOCK) { - synchronized(SEND_LOCK) - { - VMPlainDatagramSocketImpl.send(this, packet); - } - } + ByteBuffer buf = ByteBuffer.wrap(packet.getData(), + packet.getOffset(), + packet.getLength()); + InetAddress remote = packet.getAddress(); + int port = packet.getPort(); + if (remote == null) + throw new NullPointerException(); + if (port <= 0) + throw new SocketException("invalid port " + port); + channel.send(buf, new InetSocketAddress(remote, port)); + } } /** @@ -210,10 +273,16 @@ protected void receive(DatagramPacket packet) throws IOException { - synchronized(RECEIVE_LOCK) - { - VMPlainDatagramSocketImpl.receive(this, packet); - } + synchronized(RECEIVE_LOCK) + { + ByteBuffer buf = ByteBuffer.wrap(packet.getData(), + packet.getOffset(), + packet.getLength()); + SocketAddress addr = channel.receive(buf); + if (addr != null) + packet.setSocketAddress(addr); + packet.setLength(buf.position() - packet.getOffset()); + } } @@ -227,9 +296,9 @@ */ public synchronized void setOption(int option_id, Object val) throws SocketException - { - VMPlainDatagramSocketImpl.setOption(this, option_id, val); - } + { + impl.setOption(option_id, val); + } /** * Retrieves the value of an option on the socket @@ -242,16 +311,43 @@ */ public synchronized Object getOption(int option_id) throws SocketException - { - return VMPlainDatagramSocketImpl.getOption(this, option_id); - } + { + if (option_id == SO_BINDADDR) + { + try + { + InetSocketAddress local = channel.getLocalAddress(); + if (local == null) + return null; + return local.getAddress(); + } + catch (SocketException se) + { + throw se; + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } + return impl.getOption(option_id); + } /** * Closes the socket */ protected synchronized void close() { - VMPlainDatagramSocketImpl.close(this); + try + { + if (channel.getState().isValid()) + channel.close(); + } + catch (IOException ioe) + { + } } /** @@ -291,7 +387,7 @@ */ protected synchronized void join(InetAddress addr) throws IOException { - VMPlainDatagramSocketImpl.join(this,addr); + impl.join(addr); } /** @@ -303,7 +399,7 @@ */ protected synchronized void leave(InetAddress addr) throws IOException { - VMPlainDatagramSocketImpl.leave(this, addr); + impl.join(addr); } /** @@ -323,12 +419,20 @@ public void joinGroup(SocketAddress address, NetworkInterface netIf) throws IOException { - VMPlainDatagramSocketImpl.joinGroup(this, address, netIf); + if (address == null) + throw new NullPointerException(); + if (!(address instanceof InetSocketAddress)) + throw new SocketException("unknown address type"); + impl.joinGroup((InetSocketAddress) address, netIf); } public void leaveGroup(SocketAddress address, NetworkInterface netIf) throws IOException { - VMPlainDatagramSocketImpl.leaveGroup(this, address, netIf); + if (address == null) + throw new NullPointerException(); + if (!(address instanceof InetSocketAddress)) + throw new SocketException("unknown address type"); + impl.leaveGroup((InetSocketAddress) address, netIf); } } Index: gnu/java/net/PlainSocketImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/net/PlainSocketImpl.java,v retrieving revision 1.13 diff -u -r1.13 PlainSocketImpl.java --- gnu/java/net/PlainSocketImpl.java 4 Jan 2006 20:50:20 -0000 1.13 +++ gnu/java/net/PlainSocketImpl.java 15 Sep 2006 00:48:14 -0000 @@ -39,13 +39,24 @@ package gnu.java.net; +import gnu.java.nio.SelectorProviderImpl; +import gnu.java.nio.SocketChannelImpl; +import gnu.java.nio.VMChannel; +import gnu.java.security.action.GetSecurityPropertyAction; + +import java.io.EOFException; import java.io.InputStream; import java.io.IOException; +import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketException; import java.net.SocketImpl; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; /** * Written using on-line Java Platform 1.2 API Specification, as well @@ -63,17 +74,13 @@ * @author Nic Ferrier (nferrier@tapsellferrier.co.uk) * @author Aaron M. Renn (arenn@urbanophile.com) */ -public final class PlainSocketImpl extends SocketImpl +public class PlainSocketImpl extends SocketImpl { /** - * The OS file handle representing the socket. - * This is used for reads and writes to/from the socket and - * to close it. - * - * When the socket is closed this is reset to -1. + * The underlying plain socket VM implementation. */ - int native_fd = -1; + protected VMPlainSocketImpl impl; /** * A cached copy of the in stream for reading from the socket. @@ -90,7 +97,13 @@ * is being invoked on this socket. */ private boolean inChannelOperation; - + + /** + * The socket channel we use for IO operation. Package-private for + * use by inner classes. + */ + SocketChannelImpl channel; + /** * Indicates whether we should ignore whether any associated * channel is set to non-blocking mode. Certain operations @@ -117,29 +130,7 @@ */ public PlainSocketImpl() { - // Nothing to do here. - } - - protected void finalize() throws Throwable - { - synchronized (this) - { - if (native_fd != -1) - try - { - close(); - } - catch (IOException ex) - { - // Nothing we can do about it. - } - } - super.finalize(); - } - - public int getNativeFD() - { - return native_fd; + this.impl = new VMPlainSocketImpl(); } /** @@ -155,7 +146,29 @@ */ public void setOption(int optionId, Object value) throws SocketException { - VMPlainSocketImpl.setOption(this, optionId, value); + switch (optionId) + { + case IP_MULTICAST_IF: + case IP_MULTICAST_IF2: + throw new UnsupportedOperationException("FIXME"); + + case IP_MULTICAST_LOOP: + case SO_BROADCAST: + case SO_KEEPALIVE: + case SO_OOBINLINE: + case TCP_NODELAY: + case IP_TOS: + case SO_LINGER: + case SO_RCVBUF: + case SO_SNDBUF: + case SO_TIMEOUT: + case SO_REUSEADDR: + impl.setOption(optionId, value); + return; + + default: + throw new SocketException("cannot set option " + optionId); + } } /** @@ -171,17 +184,33 @@ */ public Object getOption(int optionId) throws SocketException { - return VMPlainSocketImpl.getOption(this, optionId); + if (optionId == SO_BINDADDR) + { + try + { + return channel.getVMChannel().getLocalAddress().getAddress(); + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } + if (optionId == IP_MULTICAST_IF || optionId == IP_MULTICAST_IF2) + throw new UnsupportedOperationException ("can't get option " + + optionId + " yet"); + return impl.getOption(optionId); } public void shutdownInput() throws IOException { - VMPlainSocketImpl.shutdownInput(this); + impl.shutdownInput(); } public void shutdownOutput() throws IOException { - VMPlainSocketImpl.shutdownOutput(this); + impl.shutdownOutput(); } /** @@ -195,7 +224,11 @@ */ protected synchronized void create(boolean stream) throws IOException { - VMPlainSocketImpl.create(this); + channel = new SocketChannelImpl(false); + VMChannel vmchannel = channel.getVMChannel(); + vmchannel.initSocket(stream); + channel.configureBlocking(true); + impl.getState().setChannelFD(vmchannel.getState()); } /** @@ -222,7 +255,7 @@ */ protected void connect(InetAddress addr, int port) throws IOException { - VMPlainSocketImpl.connect(this, addr, port); + connect(new InetSocketAddress(addr, port), 0); } /** @@ -236,7 +269,14 @@ protected synchronized void connect(SocketAddress address, int timeout) throws IOException { - VMPlainSocketImpl.connect(this, address, timeout); + if (channel == null) + create(true); + boolean connected = channel.connect(address, timeout); + if (!connected) + throw new SocketTimeoutException("connect timed out"); + InetSocketAddress addr = channel.getVMChannel().getPeerAddress(); + this.address = addr.getAddress(); + this.port = addr.getPort(); } /** @@ -251,7 +291,10 @@ protected synchronized void bind(InetAddress addr, int port) throws IOException { - VMPlainSocketImpl.bind(this, addr, port); + if (channel == null) + create(true); + impl.bind(new InetSocketAddress(addr, port)); + localport = channel.getVMChannel().getLocalAddress().getPort(); } /** @@ -267,7 +310,7 @@ protected synchronized void listen(int queuelen) throws IOException { - VMPlainSocketImpl.listen(this, queuelen); + impl.listen(queuelen); } /** @@ -279,7 +322,16 @@ protected synchronized void accept(SocketImpl impl) throws IOException { - VMPlainSocketImpl.accept(this, impl); + if (channel == null) + create(true); + if (!(impl instanceof PlainSocketImpl)) + throw new IOException("incompatible SocketImpl: " + + impl.getClass().getName()); + PlainSocketImpl that = (PlainSocketImpl) impl; + VMChannel c = channel.getVMChannel().accept(); + that.impl.getState().setChannelFD(c.getState()); + that.channel = new SocketChannelImpl(c); + that.setOption(SO_REUSEADDR, Boolean.TRUE); } /** @@ -292,7 +344,9 @@ */ protected int available() throws IOException { - return VMPlainSocketImpl.available(this); + if (channel == null) + throw new SocketException("not connected"); + return channel.getVMChannel().available(); } /** @@ -308,65 +362,13 @@ */ protected void close() throws IOException { - VMPlainSocketImpl.close(this); - } - - public void sendUrgentData(int data) - { - VMPlainSocketImpl.sendUrgendData(this, data); - } - - /** - * Internal method used by SocketInputStream for reading data from - * the connection. Reads up to len bytes of data into the buffer - * buf starting at offset bytes into the buffer. - * - * @return the actual number of bytes read or -1 if end of stream. - * - * @throws IOException if an error occurs - */ - protected int read(byte[] buf, int offset, int len) - throws IOException - { - return VMPlainSocketImpl.read(this, buf, offset, len); + if (impl.getState().isValid()) + impl.close(); } - /** - * Internal method used by SocketInputStream for reading data from - * the connection. Reads and returns one byte of data. - * - * @return the read byte - * - * @throws IOException if an error occurs - */ - protected int read() - throws IOException + public void sendUrgentData(int data) throws IOException { - return VMPlainSocketImpl.read(this); - } - - /** - * Internal method used by SocketOuputStream for writing data to - * the connection. Writes up to len bytes of data from the buffer - * buf starting at offset bytes into the buffer. - * - * @throws IOException If an error occurs - */ - protected void write(byte[] buf, int offset, int len) - throws IOException - { - VMPlainSocketImpl.write(this, buf, offset, len); - } - - /** - * Internal method used by SocketOuputStream for writing data to - * the connection. Writes up one byte to the socket. - * - * @throws IOException If an error occurs - */ - protected void write(int data) throws IOException - { - VMPlainSocketImpl.write(this, data); + impl.sendUrgentData(data); } /** @@ -400,6 +402,87 @@ return out; } + + public VMChannel getVMChannel() + { + if (channel == null) + return null; + return channel.getVMChannel(); + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getInetAddress() + */ + protected InetAddress getInetAddress() + { + if (channel == null) + return null; + try + { + InetSocketAddress remote = channel.getVMChannel().getPeerAddress(); + if (remote == null) + return null; + return remote.getAddress(); + } + catch (IOException ioe) + { + return null; + } + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getLocalPort() + */ + protected int getLocalPort() + { + if (channel == null) + return -1; + try + { + InetSocketAddress local = channel.getVMChannel().getLocalAddress(); + if (local == null) + return -1; + return local.getPort(); + } + catch (IOException ioe) + { + return -1; + } + } + + public InetSocketAddress getLocalAddress() + { + if (channel == null) + return null; + try + { + return channel.getVMChannel().getLocalAddress(); + } + catch (IOException ioe) + { + return null; + } + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getPort() + */ + protected int getPort() + { + if (channel == null) + return -1; + try + { + InetSocketAddress remote = channel.getVMChannel().getPeerAddress(); + if (remote == null) + return -1; + return remote.getPort(); + } + catch (IOException ioe) + { + return -1; + } + } /** * This class contains an implementation of InputStream for @@ -437,7 +520,23 @@ */ public int read() throws IOException { - return PlainSocketImpl.this.read(); + if (channel == null) + throw new SocketException("not connected"); + while (true) + { + try + { + return channel.getVMChannel().read(); + } + catch (SocketTimeoutException ste) + { + throw ste; + } + catch (InterruptedIOException iioe) + { + // Ignore; NIO may throw this; net io shouldn't + } + } } /** @@ -454,12 +553,24 @@ */ public int read (byte[] buf, int offset, int len) throws IOException { - int bytes_read = PlainSocketImpl.this.read (buf, offset, len); - - if (bytes_read == 0) - return -1; - - return bytes_read; + if (channel == null) + throw new SocketException("not connected"); + ByteBuffer b = ByteBuffer.wrap(buf, offset, len); + while (true) + { + try + { + return channel.read(b); + } + catch (SocketTimeoutException ste) + { + throw ste; + } + catch (InterruptedIOException iioe) + { + // Ignored; NIO may throw this; net IO not. + } + } } } @@ -495,7 +606,20 @@ */ public void write(int b) throws IOException { - PlainSocketImpl.this.write(b); + if (channel == null) + throw new SocketException("not connected"); + while (true) + { + try + { + channel.getVMChannel().write(b); + return; + } + catch (InterruptedIOException iioe) + { + // Ignored. + } + } } /** @@ -510,7 +634,21 @@ */ public void write (byte[] buf, int offset, int len) throws IOException { - PlainSocketImpl.this.write (buf, offset, len); + if (channel == null) + throw new SocketException("not connected"); + ByteBuffer b = ByteBuffer.wrap(buf, offset, len); + while (b.hasRemaining()) + { + try + { + if (channel.write(b) == -1) + throw new IOException("channel has been closed"); + } + catch (InterruptedIOException iioe) + { + // Ignored. + } + } } } } Index: gnu/java/nio/DatagramChannelImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/DatagramChannelImpl.java,v retrieving revision 1.15 diff -u -r1.15 DatagramChannelImpl.java --- gnu/java/nio/DatagramChannelImpl.java 27 Dec 2005 02:27:01 -0000 1.15 +++ gnu/java/nio/DatagramChannelImpl.java 15 Sep 2006 00:48:14 -0000 @@ -55,8 +55,10 @@ * @author Michael Koch */ public final class DatagramChannelImpl extends DatagramChannel + implements VMChannelOwner { private NIODatagramSocket socket; + private VMChannel channel; /** * Indicates whether this channel initiated whatever operation @@ -64,6 +66,16 @@ */ private boolean inChannelOperation; + protected DatagramChannelImpl (SelectorProvider provider) + throws IOException + { + super (provider); + socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this); + channel = new VMChannel(); + channel.initSocket(false); + configureBlocking(true); + } + /** * Indicates whether our datagram socket should ignore whether * we are set to non-blocking mode. Certain operations on our @@ -85,14 +97,6 @@ inChannelOperation = b; } - protected DatagramChannelImpl (SelectorProvider provider) - throws IOException - { - super (provider); - socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this); - configureBlocking(true); - } - public DatagramSocket socket () { return socket; @@ -101,13 +105,13 @@ protected void implCloseSelectableChannel () throws IOException { - socket.close (); + channel.close(); } protected void implConfigureBlocking (boolean blocking) throws IOException { - socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT); + channel.setBlocking(blocking); } public DatagramChannel connect (SocketAddress remote) @@ -116,20 +120,34 @@ if (!isOpen()) throw new ClosedChannelException(); - socket.connect (remote); + try + { + channel.connect((InetSocketAddress) remote, 0); + } + catch (ClassCastException cce) + { + throw new IOException("unsupported socked address type"); + } return this; } public DatagramChannel disconnect () throws IOException { - socket.disconnect (); + channel.disconnect(); return this; } - public boolean isConnected () + public boolean isConnected() { - return socket.isConnected (); + try + { + return channel.getPeerAddress() != null; + } + catch (IOException ioe) + { + return false; + } } public int write (ByteBuffer src) @@ -138,7 +156,7 @@ if (!isConnected ()) throw new NotYetConnectedException (); - return send (src, socket.getRemoteSocketAddress()); + return channel.write(src); } public long write (ByteBuffer[] srcs, int offset, int length) @@ -152,13 +170,11 @@ || (length < 0) || (length > (srcs.length - offset))) throw new IndexOutOfBoundsException(); - - long result = 0; - - for (int index = offset; index < offset + length; index++) - result += write (srcs [index]); - return result; + /* We are connected, meaning we will write these bytes to + * the host we connected to, so we don't need to explicitly + * give the host. */ + return channel.writeGathering(srcs, offset, length); } public int read (ByteBuffer dst) @@ -167,9 +183,7 @@ if (!isConnected ()) throw new NotYetConnectedException (); - int remaining = dst.remaining(); - receive (dst); - return remaining - dst.remaining(); + return channel.read(dst); } public long read (ByteBuffer[] dsts, int offset, int length) @@ -184,12 +198,8 @@ || (length > (dsts.length - offset))) throw new IndexOutOfBoundsException(); - long result = 0; - - for (int index = offset; index < offset + length; index++) - result += read (dsts [index]); - - return result; + /* Likewise, see the comment int write above. */ + return channel.readScattering(dsts, offset, length); } public SocketAddress receive (ByteBuffer dst) @@ -200,49 +210,12 @@ try { - DatagramPacket packet; - int len = dst.remaining(); - - if (dst.hasArray()) - { - packet = new DatagramPacket (dst.array(), - dst.arrayOffset() + dst.position(), - len); - } - else - { - packet = new DatagramPacket (new byte [len], len); - } - - boolean completed = false; - - try - { - begin(); - setInChannelOperation(true); - socket.receive (packet); - completed = true; - } - finally - { - end (completed); - setInChannelOperation(false); - } - - if (!dst.hasArray()) - { - dst.put (packet.getData(), packet.getOffset(), packet.getLength()); - } - else - { - dst.position (dst.position() + packet.getLength()); - } - - return packet.getSocketAddress(); + begin(); + return channel.receive(dst); } - catch (SocketTimeoutException e) + finally { - return null; + end(true); } } @@ -252,46 +225,18 @@ if (!isOpen()) throw new ClosedChannelException(); - if (target instanceof InetSocketAddress - && ((InetSocketAddress) target).isUnresolved()) - throw new IOException("Target address not resolved"); - - byte[] buffer; - int offset = 0; - int len = src.remaining(); + if (!(target instanceof InetSocketAddress)) + throw new IOException("can only send to inet socket addresses"); - if (src.hasArray()) - { - buffer = src.array(); - offset = src.arrayOffset() + src.position(); - } - else - { - buffer = new byte [len]; - src.get (buffer); - } - - DatagramPacket packet = new DatagramPacket (buffer, offset, len, target); - - boolean completed = false; - try - { - begin(); - setInChannelOperation(true); - socket.send(packet); - completed = true; - } - finally - { - end (completed); - setInChannelOperation(false); - } - - if (src.hasArray()) - { - src.position (src.position() + len); - } + InetSocketAddress dst = (InetSocketAddress) target; + if (dst.isUnresolved()) + throw new IOException("Target address not resolved"); - return len; + return channel.send(src, dst); + } + + public VMChannel getVMChannel() + { + return channel; } } Index: gnu/java/nio/DatagramChannelSelectionKey.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/DatagramChannelSelectionKey.java,v retrieving revision 1.3 diff -u -r1.3 DatagramChannelSelectionKey.java --- gnu/java/nio/DatagramChannelSelectionKey.java 2 Jul 2005 20:32:13 -0000 1.3 +++ gnu/java/nio/DatagramChannelSelectionKey.java 15 Sep 2006 00:48:14 -0000 @@ -38,6 +38,7 @@ package gnu.java.nio; +import java.io.IOException; import java.nio.channels.spi.AbstractSelectableChannel; /** @@ -52,10 +53,16 @@ super (channel, selector); } + // FIXME don't use file descriptor integers public int getNativeFD() { - NIODatagramSocket socket = - (NIODatagramSocket) ((DatagramChannelImpl) ch).socket(); - return socket.getPlainDatagramSocketImpl().getNativeFD(); + try + { + return ((DatagramChannelImpl) ch).getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + throw new IllegalStateException(ioe); + } } } Index: gnu/java/nio/FileLockImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/FileLockImpl.java,v retrieving revision 1.10 diff -u -r1.10 FileLockImpl.java --- gnu/java/nio/FileLockImpl.java 31 Jul 2005 16:00:42 -0000 1.10 +++ gnu/java/nio/FileLockImpl.java 15 Sep 2006 00:48:14 -0000 @@ -38,8 +38,6 @@ package gnu.java.nio; -import gnu.java.nio.channels.FileChannelImpl; - import java.io.IOException; import java.nio.channels.FileLock; Index: gnu/java/nio/NIOSocket.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/NIOSocket.java,v retrieving revision 1.4 diff -u -r1.4 NIOSocket.java --- gnu/java/nio/NIOSocket.java 2 Jul 2005 20:32:13 -0000 1.4 +++ gnu/java/nio/NIOSocket.java 15 Sep 2006 00:48:14 -0000 @@ -48,30 +48,33 @@ */ public final class NIOSocket extends Socket { - private PlainSocketImpl impl; private SocketChannelImpl channel; - protected NIOSocket (PlainSocketImpl impl, SocketChannelImpl channel) + protected NIOSocket (SocketChannelImpl channel) throws IOException { - super (impl); - this.impl = impl; + super (new NIOSocketImpl(channel)); this.channel = channel; } - public final PlainSocketImpl getPlainSocketImpl() - { - return impl; - } + //public final PlainSocketImpl getPlainSocketImpl() + //{ + // return impl; + //} - final void setChannel (SocketChannelImpl channel) - { - this.impl = channel.getPlainSocketImpl(); - this.channel = channel; - } + //final void setChannel (SocketChannelImpl channel) + //{ + // this.impl = channel.getPlainSocketImpl(); + // this.channel = channel; + //} public final SocketChannel getChannel() { return channel; } + + public boolean isConnected() + { + return channel.isConnected(); + } } Index: gnu/java/nio/PipeImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/PipeImpl.java,v retrieving revision 1.12 diff -u -r1.12 PipeImpl.java --- gnu/java/nio/PipeImpl.java 14 May 2006 03:34:54 -0000 1.12 +++ gnu/java/nio/PipeImpl.java 15 Sep 2006 00:48:14 -0000 @@ -46,22 +46,21 @@ class PipeImpl extends Pipe { public static final class SourceChannelImpl extends Pipe.SourceChannel + implements VMChannelOwner { - private int native_fd; private VMChannel vmch; public SourceChannelImpl (SelectorProvider selectorProvider, - int native_fd) + VMChannel channel) { super (selectorProvider); - this.native_fd = native_fd; - vmch = VMChannel.getVMChannel(this); + vmch = channel; } protected final void implCloseSelectableChannel() throws IOException { - throw new Error ("Not implemented"); + vmch.close(); } protected void implConfigureBlocking (boolean blocking) @@ -94,30 +93,29 @@ return vmch.readScattering(srcs, offset, len); } - - public final int getNativeFD() + + public VMChannel getVMChannel() { - return native_fd; + return vmch; } } public static final class SinkChannelImpl extends Pipe.SinkChannel + implements VMChannelOwner { - private int native_fd; private VMChannel vmch; public SinkChannelImpl (SelectorProvider selectorProvider, - int native_fd) + VMChannel channel) { super (selectorProvider); - this.native_fd = native_fd; - vmch = VMChannel.getVMChannel(this); + vmch = channel; } protected final void implCloseSelectableChannel() throws IOException { - throw new Error ("Not implemented"); + vmch.close(); } protected final void implConfigureBlocking (boolean blocking) @@ -149,10 +147,10 @@ return vmch.writeGathering(srcs, offset, len); } - - public final int getNativeFD() + + public VMChannel getVMChannel() { - return native_fd; + return vmch; } } @@ -163,7 +161,9 @@ throws IOException { super(); - VMPipe.init (this, provider); + VMChannel[] pipe = VMPipe.pipe(); + sink = new SinkChannelImpl(provider, pipe[0]); + source = new SourceChannelImpl(provider, pipe[1]); } public Pipe.SinkChannel sink() Index: gnu/java/nio/SelectionKeyImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SelectionKeyImpl.java,v retrieving revision 1.10 diff -u -r1.10 SelectionKeyImpl.java --- gnu/java/nio/SelectionKeyImpl.java 31 Jul 2006 22:08:00 -0000 1.10 +++ gnu/java/nio/SelectionKeyImpl.java 15 Sep 2006 00:48:14 -0000 @@ -106,5 +106,6 @@ return impl; } + /* @deprecated */ public abstract int getNativeFD(); } Index: gnu/java/nio/SelectorProviderImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SelectorProviderImpl.java,v retrieving revision 1.8 diff -u -r1.8 SelectorProviderImpl.java --- gnu/java/nio/SelectorProviderImpl.java 2 Jul 2005 20:32:13 -0000 1.8 +++ gnu/java/nio/SelectorProviderImpl.java 15 Sep 2006 00:48:14 -0000 @@ -37,6 +37,9 @@ package gnu.java.nio; + +import gnu.classpath.SystemProperties; + import java.io.IOException; import java.nio.channels.DatagramChannel; import java.nio.channels.Pipe; @@ -47,6 +50,10 @@ public class SelectorProviderImpl extends SelectorProvider { + private static final String SELECTOR_IMPL_KQUEUE = "kqueue"; + private static final String SELECTOR_IMPL_EPOLL = "epoll"; + private static final String SELECTOR_IMPL = "gnu.java.nio.selectorImpl"; + public SelectorProviderImpl () { } @@ -66,6 +73,16 @@ public AbstractSelector openSelector () throws IOException { + String selectorImpl = "default"; + if (KqueueSelectorImpl.kqueue_supported()) + selectorImpl = SELECTOR_IMPL_KQUEUE; + selectorImpl = SystemProperties.getProperty(SELECTOR_IMPL, selectorImpl); + + if (selectorImpl.equals(SELECTOR_IMPL_KQUEUE)) + return new KqueueSelectorImpl(this); + if (selectorImpl.equals(SELECTOR_IMPL_EPOLL)) + throw new UnsupportedOperationException("epoll selector not yet implemented"); + return new SelectorImpl (this); } Index: gnu/java/nio/ServerSocketChannelImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/ServerSocketChannelImpl.java,v retrieving revision 1.14 diff -u -r1.14 ServerSocketChannelImpl.java --- gnu/java/nio/ServerSocketChannelImpl.java 2 Jul 2005 20:32:13 -0000 1.14 +++ gnu/java/nio/ServerSocketChannelImpl.java 15 Sep 2006 00:48:14 -0000 @@ -48,7 +48,9 @@ import java.nio.channels.spi.SelectorProvider; public final class ServerSocketChannelImpl extends ServerSocketChannel + implements VMChannelOwner { + private VMChannel channel; private NIOServerSocket serverSocket; private boolean connected; @@ -56,13 +58,15 @@ throws IOException { super (provider); - serverSocket = new NIOServerSocket (this); + serverSocket = new NIOServerSocket(this); + channel = serverSocket.getPlainSocketImpl().getVMChannel(); configureBlocking(true); } + // XXX do we need this? public void finalizer() { - if (connected) + if (channel.getState().isValid()) { try { @@ -77,12 +81,12 @@ protected void implCloseSelectableChannel () throws IOException { connected = false; - serverSocket.close(); + channel.close(); } protected void implConfigureBlocking (boolean blocking) throws IOException { - serverSocket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT); + channel.setBlocking(blocking); } public SocketChannel accept () throws IOException @@ -98,27 +102,28 @@ try { begin(); - serverSocket.getPlainSocketImpl().setInChannelOperation(true); - // indicate that a channel is initiating the accept operation - // so that the socket ignores the fact that we might be in - // non-blocking mode. - NIOSocket socket = (NIOSocket) serverSocket.accept(); - completed = true; - return socket.getChannel(); - } - catch (SocketTimeoutException e) - { - return null; + VMChannel client = channel.accept(); + if (client == null) + return null; + else + { + completed = true; + return new SocketChannelImpl(provider(), client, false); + } } finally { - serverSocket.getPlainSocketImpl().setInChannelOperation(false); end (completed); } } - public ServerSocket socket () + public ServerSocket socket() { return serverSocket; } + + public VMChannel getVMChannel() + { + return channel; + } } Index: gnu/java/nio/ServerSocketChannelSelectionKey.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java,v retrieving revision 1.3 diff -u -r1.3 ServerSocketChannelSelectionKey.java --- gnu/java/nio/ServerSocketChannelSelectionKey.java 2 Jul 2005 20:32:13 -0000 1.3 +++ gnu/java/nio/ServerSocketChannelSelectionKey.java 15 Sep 2006 00:48:14 -0000 @@ -38,6 +38,7 @@ package gnu.java.nio; +import java.io.IOException; import java.nio.channels.spi.AbstractSelectableChannel; public final class ServerSocketChannelSelectionKey @@ -49,10 +50,16 @@ super (channel, selector); } + // FIXME don't use file descriptor integers public int getNativeFD() { - NIOServerSocket socket = - (NIOServerSocket) ((ServerSocketChannelImpl) ch).socket(); - return socket.getPlainSocketImpl().getNativeFD(); + try + { + return ((ServerSocketChannelImpl) ch).getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + throw new IllegalStateException(ioe); + } } } Index: gnu/java/nio/SocketChannelImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SocketChannelImpl.java,v retrieving revision 1.29 diff -u -r1.29 SocketChannelImpl.java --- gnu/java/nio/SocketChannelImpl.java 27 Dec 2005 02:27:01 -0000 1.29 +++ gnu/java/nio/SocketChannelImpl.java 15 Sep 2006 00:48:14 -0000 @@ -39,15 +39,20 @@ package gnu.java.nio; import gnu.java.net.PlainSocketImpl; +import gnu.java.net.VMPlainSocketImpl; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; +import java.net.SocketException; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; +import java.nio.ReadOnlyBufferException; import java.nio.channels.AlreadyConnectedException; import java.nio.channels.ClosedChannelException; import java.nio.channels.ConnectionPendingException; @@ -61,28 +66,57 @@ import java.nio.channels.spi.SelectorProvider; public final class SocketChannelImpl extends SocketChannel + implements VMChannelOwner { - private PlainSocketImpl impl; + private VMChannel channel; + //private PlainSocketImpl impl; private NIOSocket socket; private boolean connectionPending; + private boolean connected; + private InetSocketAddress connectAddress; + + public SocketChannelImpl(boolean create) throws IOException + { + // XXX consider adding security check; this is used by + // PlainSocketImpl. + this(new SelectorProviderImpl(), create); + } + + public SocketChannelImpl(VMChannel channel) throws IOException + { + this(new SelectorProviderImpl(), channel, false); + } + + SocketChannelImpl(SelectorProvider provider) throws IOException + { + this(provider, true); + } - SocketChannelImpl (SelectorProvider provider) + SocketChannelImpl(SelectorProvider provider, boolean create) + throws IOException + { + this(provider, new VMChannel(), create); + } + + SocketChannelImpl(SelectorProvider provider, VMChannel channel, boolean create) throws IOException { super (provider); - impl = new PlainSocketImpl(); - socket = new NIOSocket (impl, this); + this.channel = channel; + if (create) + channel.initSocket(true); + socket = new NIOSocket(this); configureBlocking(true); } - SocketChannelImpl (SelectorProvider provider, + /*SocketChannelImpl (SelectorProvider provider, NIOSocket socket) throws IOException { super (provider); this.impl = socket.getPlainSocketImpl(); this.socket = socket; - } + }*/ public void finalizer() { @@ -98,23 +132,28 @@ } } - PlainSocketImpl getPlainSocketImpl() - { - return impl; - } + //PlainSocketImpl getPlainSocketImpl() + //{ + // return null; // XXX + //} - protected void implCloseSelectableChannel () throws IOException + protected void implCloseSelectableChannel() throws IOException { - socket.close(); + channel.close(); } protected void implConfigureBlocking (boolean blocking) throws IOException { - socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT); + channel.setBlocking(blocking); } public boolean connect (SocketAddress remote) throws IOException { + return connect(remote, 0); + } + + public boolean connect (SocketAddress remote, int timeout) throws IOException + { if (!isOpen()) throw new ClosedChannelException(); @@ -126,40 +165,15 @@ if (!(remote instanceof InetSocketAddress)) throw new UnsupportedAddressTypeException(); + + connectAddress = (InetSocketAddress) remote; - if (((InetSocketAddress) remote).isUnresolved()) + if (connectAddress.isUnresolved()) throw new UnresolvedAddressException(); - try - { - socket.getPlainSocketImpl().setInChannelOperation(true); - // indicate that a channel is initiating the accept operation - // so that the socket ignores the fact that we might be in - // non-blocking mode. - - if (isBlocking()) - { - // Do blocking connect. - socket.connect (remote); - return true; - } - - // Do non-blocking connect. - try - { - socket.connect (remote, NIOConstants.DEFAULT_TIMEOUT); - return true; - } - catch (SocketTimeoutException e) - { - connectionPending = true; - return false; - } - } - finally - { - socket.getPlainSocketImpl().setInChannelOperation(false); - } + connected = channel.connect(connectAddress, timeout); + connectionPending = !connected; + return connected; } public boolean finishConnect () @@ -168,37 +182,30 @@ if (!isOpen()) throw new ClosedChannelException(); - if (!isConnected() && !connectionPending) - throw new NoConnectionPendingException(); - if (isConnected()) - return true; - - // FIXME: Handle blocking/non-blocking mode. - - Selector selector = provider().openSelector(); - register(selector, SelectionKey.OP_CONNECT); - - if (isBlocking()) { - selector.select(); // blocking until channel is connected. connectionPending = false; return true; } - - int ready = selector.selectNow(); // non-blocking - if (ready == 1) - { - connectionPending = false; - return true; - } - + + if (!connectionPending) + throw new NoConnectionPendingException(); + return false; } - public boolean isConnected () + public boolean isConnected() { - return socket.isConnected(); + try + { + InetSocketAddress remote = channel.getPeerAddress(); + return remote != null; + } + catch (IOException ioe) + { + ioe.printStackTrace(System.out); + return false; + } } public boolean isConnectionPending () @@ -216,52 +223,7 @@ if (!isConnected()) throw new NotYetConnectedException(); - byte[] data; - int offset = 0; - InputStream input = socket.getInputStream(); - int available = input.available(); - int len = dst.remaining(); - - if ((! isBlocking()) && available == 0) - return 0; - - if (dst.hasArray()) - { - offset = dst.arrayOffset() + dst.position(); - data = dst.array(); - } - else - { - data = new byte [len]; - } - - int readBytes = 0; - boolean completed = false; - - try - { - begin(); - socket.getPlainSocketImpl().setInChannelOperation(true); - readBytes = input.read (data, offset, len); - completed = true; - } - finally - { - end (completed); - socket.getPlainSocketImpl().setInChannelOperation(false); - } - - if (readBytes > 0) - if (dst.hasArray()) - { - dst.position (dst.position() + readBytes); - } - else - { - dst.put (data, offset, readBytes); - } - - return readBytes; + return channel.read(dst); } public long read (ByteBuffer[] dsts, int offset, int length) @@ -275,61 +237,19 @@ || (length < 0) || (length > (dsts.length - offset))) throw new IndexOutOfBoundsException(); - - long readBytes = 0; - - for (int index = offset; index < length; index++) - readBytes += read (dsts [index]); - - return readBytes; + + return channel.readScattering(dsts, offset, length); } - public int write (ByteBuffer src) - throws IOException + public int write(ByteBuffer src) throws IOException { if (!isConnected()) throw new NotYetConnectedException(); - - byte[] data; - int offset = 0; - int len = src.remaining(); - - if (!src.hasArray()) - { - data = new byte [len]; - src.get (data, 0, len); - } - else - { - offset = src.arrayOffset() + src.position(); - data = src.array(); - } - - OutputStream output = socket.getOutputStream(); - boolean completed = false; - - try - { - begin(); - socket.getPlainSocketImpl().setInChannelOperation(true); - output.write (data, offset, len); - completed = true; - } - finally - { - end (completed); - socket.getPlainSocketImpl().setInChannelOperation(false); - } - if (src.hasArray()) - { - src.position (src.position() + len); - } - - return len; + return channel.write(src); } - public long write (ByteBuffer[] srcs, int offset, int length) + public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if (!isConnected()) @@ -340,12 +260,13 @@ || (length < 0) || (length > (srcs.length - offset))) throw new IndexOutOfBoundsException(); - - long writtenBytes = 0; - - for (int index = offset; index < length; index++) - writtenBytes += write (srcs [index]); - return writtenBytes; + return channel.writeGathering(srcs, offset, length); + } + + public VMChannel getVMChannel() + { + // XXX security check? + return channel; } } Index: gnu/java/nio/SocketChannelSelectionKey.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SocketChannelSelectionKey.java,v retrieving revision 1.3 diff -u -r1.3 SocketChannelSelectionKey.java --- gnu/java/nio/SocketChannelSelectionKey.java 2 Jul 2005 20:32:13 -0000 1.3 +++ gnu/java/nio/SocketChannelSelectionKey.java 15 Sep 2006 00:48:14 -0000 @@ -38,6 +38,7 @@ package gnu.java.nio; +import java.io.IOException; import java.nio.channels.spi.AbstractSelectableChannel; public final class SocketChannelSelectionKey @@ -49,10 +50,16 @@ super (channel, selector); } + // FIXME don't use file descriptor integers public int getNativeFD() { - NIOSocket socket = - (NIOSocket) ((SocketChannelImpl) ch).socket(); - return socket.getPlainSocketImpl().getNativeFD(); + try + { + return ((SocketChannelImpl) ch).getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + throw new IllegalStateException(ioe); + } } } Index: gnu/java/nio/SocketChannelSelectionKeyImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java,v retrieving revision 1.1 diff -u -r1.1 SocketChannelSelectionKeyImpl.java --- gnu/java/nio/SocketChannelSelectionKeyImpl.java 14 May 2006 03:34:54 -0000 1.1 +++ gnu/java/nio/SocketChannelSelectionKeyImpl.java 15 Sep 2006 00:48:14 -0000 @@ -38,6 +38,8 @@ package gnu.java.nio; +import java.io.IOException; + /** * @author Michael Barker @@ -63,7 +65,14 @@ */ public int getNativeFD() { - return ch.getPlainSocketImpl().getNativeFD(); + try + { + return ch.getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + return 0; // FIXME + } } } Index: gnu/java/nio/channels/FileChannelImpl.java =================================================================== RCS file: gnu/java/nio/channels/FileChannelImpl.java diff -N gnu/java/nio/channels/FileChannelImpl.java --- gnu/java/nio/channels/FileChannelImpl.java 14 May 2006 03:34:55 -0000 1.22 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,553 +0,0 @@ -/* FileChannelImpl.java -- - Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package gnu.java.nio.channels; - -import gnu.classpath.Configuration; -import gnu.java.nio.FileLockImpl; -import gnu.java.nio.VMChannel; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.nio.channels.NonReadableChannelException; -import java.nio.channels.NonWritableChannelException; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; - -/** - * This file is not user visible ! - * But alas, Java does not have a concept of friendly packages - * so this class is public. - * Instances of this class are created by invoking getChannel - * Upon a Input/Output/RandomAccessFile object. - */ -public final class FileChannelImpl extends FileChannel -{ - // These are mode values for open(). - public static final int READ = 1; - public static final int WRITE = 2; - public static final int APPEND = 4; - - // EXCL is used only when making a temp file. - public static final int EXCL = 8; - public static final int SYNC = 16; - public static final int DSYNC = 32; - - public static FileChannelImpl in; - public static FileChannelImpl out; - public static FileChannelImpl err; - - private static native void init(); - - static - { - if (Configuration.INIT_LOAD_LIBRARY) - { - System.loadLibrary("javanio"); - } - - init(); - - in = new FileChannelImpl(0, READ); - out = new FileChannelImpl(1, WRITE); - err = new FileChannelImpl(2, WRITE); - } - - /** - * This is the actual native file descriptor value - */ - // System's notion of file descriptor. It might seem redundant to - // initialize this given that it is reassigned in the constructors. - // However, this is necessary because if open() throws an exception - // we want to make sure this has the value -1. This is the most - // efficient way to accomplish that. - private int fd = -1; - private VMChannel ch; - - private int mode; - - final String description; - - /* Open a file. MODE is a combination of the above mode flags. */ - /* This is a static factory method, so that VM implementors can decide - * substitute subclasses of FileChannelImpl. */ - public static FileChannelImpl create(File file, int mode) - throws FileNotFoundException - { - return new FileChannelImpl(file, mode); - } - - private FileChannelImpl(File file, int mode) - throws FileNotFoundException - { - String path = file.getPath(); - description = path; - fd = open (path, mode); - this.mode = mode; - this.ch = VMChannel.getVMChannel(this); - - // First open the file and then check if it is a a directory - // to avoid race condition. - if (file.isDirectory()) - { - try - { - close(); - } - catch (IOException e) - { - /* ignore it */ - } - - throw new FileNotFoundException(description + " is a directory"); - } - } - - /** - * Constructor for default channels in, out and err. - * - * Used by init() (native code). - * - * @param fd the file descriptor (0, 1, 2 for stdin, stdout, stderr). - * - * @param mode READ or WRITE - */ - FileChannelImpl (int fd, int mode) - { - this.fd = fd; - this.mode = mode; - this.description = "descriptor(" + fd + ")"; - this.ch = VMChannel.getVMChannel(this); - } - - private native int open (String path, int mode) throws FileNotFoundException; - - public native int available () throws IOException; - private native long implPosition () throws IOException; - private native void seek (long newPosition) throws IOException; - private native void implTruncate (long size) throws IOException; - - public native void unlock (long pos, long len) throws IOException; - - public native long size () throws IOException; - - protected native void implCloseChannel() throws IOException; - - /** - * Makes sure the Channel is properly closed. - */ - protected void finalize() throws IOException - { - if (fd != -1) - close(); - } - - public int read (ByteBuffer dst) throws IOException - { - /* - int result; - byte[] buffer = new byte [dst.remaining ()]; - - result = read (buffer, 0, buffer.length); - - if (result > 0) - dst.put (buffer, 0, result); - - return result; - */ - return ch.read(dst); - } - - public int read (ByteBuffer dst, long position) - throws IOException - { - if (position < 0) - throw new IllegalArgumentException ("position: " + position); - long oldPosition = implPosition (); - position (position); - int result = read(dst); - position (oldPosition); - - return result; - } - - public native int read () - throws IOException; - - public native int read (byte[] buffer, int offset, int length) - throws IOException; - - public long read (ByteBuffer[] dsts, int offset, int length) - throws IOException - { - return ch.readScattering(dsts, offset, length); - } - - public int write (ByteBuffer src) throws IOException - { - return ch.write(src); - } - - public int write (ByteBuffer src, long position) - throws IOException - { - if (position < 0) - throw new IllegalArgumentException ("position: " + position); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & WRITE) == 0) - throw new NonWritableChannelException (); - - int result; - long oldPosition; - - oldPosition = implPosition (); - seek (position); - result = write(src); - seek (oldPosition); - - return result; - } - - public native void write (byte[] buffer, int offset, int length) - throws IOException; - - public native void write (int b) throws IOException; - - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - return ch.writeGathering(srcs, offset, length); - } - - public native MappedByteBuffer mapImpl (char mode, long position, int size) - throws IOException; - - public MappedByteBuffer map (FileChannel.MapMode mode, - long position, long size) - throws IOException - { - char nmode = 0; - if (mode == MapMode.READ_ONLY) - { - nmode = 'r'; - if ((this.mode & READ) == 0) - throw new NonReadableChannelException(); - } - else if (mode == MapMode.READ_WRITE || mode == MapMode.PRIVATE) - { - nmode = mode == MapMode.READ_WRITE ? '+' : 'c'; - if ((this.mode & WRITE) != WRITE) - throw new NonWritableChannelException(); - if ((this.mode & READ) != READ) - throw new NonReadableChannelException(); - } - else - throw new IllegalArgumentException ("mode: " + mode); - - if (position < 0 || size < 0 || size > Integer.MAX_VALUE) - throw new IllegalArgumentException ("position: " + position - + ", size: " + size); - return mapImpl(nmode, position, (int) size); - } - - /** - * msync with the disk - */ - public void force (boolean metaData) throws IOException - { - if (!isOpen ()) - throw new ClosedChannelException (); - - force (); - } - - private native void force (); - - // like transferTo, but with a count of less than 2Gbytes - private int smallTransferTo (long position, int count, - WritableByteChannel target) - throws IOException - { - ByteBuffer buffer; - try - { - // Try to use a mapped buffer if we can. If this fails for - // any reason we'll fall back to using a ByteBuffer. - buffer = map (MapMode.READ_ONLY, position, count); - } - catch (IOException e) - { - buffer = ByteBuffer.allocate (count); - read (buffer, position); - buffer.flip(); - } - - return target.write (buffer); - } - - public long transferTo (long position, long count, - WritableByteChannel target) - throws IOException - { - if (position < 0 - || count < 0) - throw new IllegalArgumentException ("position: " + position - + ", count: " + count); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & READ) == 0) - throw new NonReadableChannelException (); - - final int pageSize = 65536; - long total = 0; - - while (count > 0) - { - int transferred - = smallTransferTo (position, (int)Math.min (count, pageSize), - target); - if (transferred < 0) - break; - total += transferred; - position += transferred; - count -= transferred; - } - - return total; - } - - // like transferFrom, but with a count of less than 2Gbytes - private int smallTransferFrom (ReadableByteChannel src, long position, - int count) - throws IOException - { - ByteBuffer buffer = null; - - if (src instanceof FileChannel) - { - try - { - // Try to use a mapped buffer if we can. If this fails - // for any reason we'll fall back to using a ByteBuffer. - buffer = ((FileChannel)src).map (MapMode.READ_ONLY, position, - count); - } - catch (IOException e) - { - } - } - - if (buffer == null) - { - buffer = ByteBuffer.allocate ((int) count); - src.read (buffer); - buffer.flip(); - } - - return write (buffer, position); - } - - public long transferFrom (ReadableByteChannel src, long position, - long count) - throws IOException - { - if (position < 0 - || count < 0) - throw new IllegalArgumentException ("position: " + position - + ", count: " + count); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & WRITE) == 0) - throw new NonWritableChannelException (); - - final int pageSize = 65536; - long total = 0; - - while (count > 0) - { - int transferred = smallTransferFrom (src, position, - (int)Math.min (count, pageSize)); - if (transferred < 0) - break; - total += transferred; - position += transferred; - count -= transferred; - } - - return total; - } - - // Shared sanity checks between lock and tryLock methods. - private void lockCheck(long position, long size, boolean shared) - throws IOException - { - if (position < 0 - || size < 0) - throw new IllegalArgumentException ("position: " + position - + ", size: " + size); - - if (!isOpen ()) - throw new ClosedChannelException(); - - if (shared && ((mode & READ) == 0)) - throw new NonReadableChannelException(); - - if (!shared && ((mode & WRITE) == 0)) - throw new NonWritableChannelException(); - } - - public FileLock tryLock (long position, long size, boolean shared) - throws IOException - { - lockCheck(position, size, shared); - - boolean completed = false; - try - { - begin(); - boolean lockable = lock(position, size, shared, false); - completed = true; - return (lockable - ? new FileLockImpl(this, position, size, shared) - : null); - } - finally - { - end(completed); - } - } - - /** Try to acquire a lock at the given position and size. - * On success return true. - * If wait as specified, block until we can get it. - * Otherwise return false. - */ - private native boolean lock(long position, long size, - boolean shared, boolean wait) throws IOException; - - public FileLock lock (long position, long size, boolean shared) - throws IOException - { - lockCheck(position, size, shared); - - boolean completed = false; - try - { - boolean lockable = lock(position, size, shared, true); - completed = true; - return (lockable - ? new FileLockImpl(this, position, size, shared) - : null); - } - finally - { - end(completed); - } - } - - public long position () - throws IOException - { - if (!isOpen ()) - throw new ClosedChannelException (); - - return implPosition (); - } - - public FileChannel position (long newPosition) - throws IOException - { - if (newPosition < 0) - throw new IllegalArgumentException ("newPosition: " + newPosition); - - if (!isOpen ()) - throw new ClosedChannelException (); - - // FIXME note semantics if seeking beyond eof. - // We should seek lazily - only on a write. - seek (newPosition); - return this; - } - - public FileChannel truncate (long size) - throws IOException - { - if (size < 0) - throw new IllegalArgumentException ("size: " + size); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & WRITE) == 0) - throw new NonWritableChannelException (); - - if (size < size ()) - implTruncate (size); - - return this; - } - - public String toString() - { - return (this.getClass() - + "[fd=" + fd - + ",mode=" + mode + "," - + description + "]"); - } - - /** - * @return The native file descriptor. - */ - public int getNativeFD() - { - return fd; - } -} Index: vm/reference/gnu/java/net/VMPlainSocketImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/vm/reference/gnu/java/net/VMPlainSocketImpl.java,v retrieving revision 1.3 diff -u -r1.3 VMPlainSocketImpl.java --- vm/reference/gnu/java/net/VMPlainSocketImpl.java 12 Jan 2006 13:42:40 -0000 1.3 +++ vm/reference/gnu/java/net/VMPlainSocketImpl.java 15 Sep 2006 00:48:14 -0000 @@ -38,8 +38,11 @@ package gnu.java.net; import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.NetworkInterface; import java.net.SocketAddress; import java.net.SocketException; import java.net.SocketImpl; @@ -47,6 +50,8 @@ import java.net.UnknownHostException; import gnu.classpath.Configuration; +import gnu.java.nio.VMChannel; +import gnu.java.nio.VMChannel.State; /** * The VM interface for {@link gnu.java.net.PlainSocketImpl}. @@ -56,6 +61,8 @@ */ public final class VMPlainSocketImpl { + private final State nfd; + /** * Static initializer to load native library. */ @@ -66,249 +73,333 @@ System.loadLibrary("javanet"); } } + + public VMPlainSocketImpl() + { + // XXX consider adding security check here. + nfd = new State(); + } + + public VMPlainSocketImpl(VMChannel channel) throws IOException + { + this(); + nfd.setChannelFD(channel.getState()); + } + + public State getState() + { + return nfd; + } - /** - * Sets the specified option on a socket to the passed in object. - * The optionId parameter is one of the defined constants in - * the SocketImpl interface. - * - * @param socket the socket object - * @param optionId the identifier of the option - * @param value the value to set the option to - * - * @throws SocketException if an error occurs - */ - static native void setOption(PlainSocketImpl socket, int optionId, Object value) - throws SocketException; - - /** - * Returns the current setting of the specified option. The optionId - * is one of the defined constants in this interface. - * - * @param socket the socket object - * @param optionId the option identifier - * - * @return the current value of the option - * - * @throws SocketException ff an error occurs - */ - static native Object getOption(PlainSocketImpl socket, int optionId) + public void setOption(int optionId, Object optionValue) + throws SocketException + { + int value; + if (optionValue instanceof Integer) + value = ((Integer) optionValue).intValue(); + else if (optionValue instanceof Boolean) + value = ((Boolean) optionValue).booleanValue() ? 1 : 0; + else + throw new IllegalArgumentException("option value type " + + optionValue.getClass().getName()); + + try + { + setOption(nfd.getNativeFD(), optionId, value); + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } + + private static native void setOption(int fd, int id, int value) throws SocketException; /** - * Creates a new socket that is not bound to any local address/port and - * is not connected to any remote address/port. - * - * @param socket the socket object - * - * @throws IOException if something goes wrong while creating the socket + * Get a socket option. This implementation is only required to support + * socket options that are boolean values, which include: + * + * SocketOptions.IP_MULTICAST_LOOP + * SocketOptions.SO_BROADCAST + * SocketOptions.SO_KEEPALIVE + * SocketOptions.SO_OOBINLINE + * SocketOptions.TCP_NODELAY + * + * and socket options that are integer values, which include: + * + * SocketOptions.IP_TOS + * SocketOptions.SO_LINGER + * SocketOptions.SO_RCVBUF + * SocketOptions.SO_SNDBUF + * SocketOptions.SO_TIMEOUT + * + * @param optionId The option ID to fetch. + * @return A {@link Boolean} or {@link Integer} containing the socket + * option. + * @throws SocketException */ - static native void create(PlainSocketImpl socket) throws IOException; - - /** - * Connects to the remote address and port specified as arguments. - * - * @param socket the socket object - * @param addr the remote address to connect to - * @param port the remote port to connect to - * - * @throws IOException if an error occurs + public Object getOption(int optionId) throws SocketException + { + int value; + try + { + value = getOption(nfd.getNativeFD(), optionId); + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + + switch (optionId) + { + case SocketOptions.IP_MULTICAST_LOOP: + case SocketOptions.SO_BROADCAST: + case SocketOptions.SO_KEEPALIVE: + case SocketOptions.SO_OOBINLINE: + case SocketOptions.TCP_NODELAY: + return Boolean.valueOf(value != 0); + + case SocketOptions.IP_TOS: + case SocketOptions.SO_LINGER: + case SocketOptions.SO_RCVBUF: + case SocketOptions.SO_SNDBUF: + case SocketOptions.SO_TIMEOUT: + return new Integer(value); + + default: + throw new SocketException("getting option " + optionId + + " not supported here"); + } + } + + private static native int getOption(int fd, int id) throws SocketException; + + /** + * Binds this socket to the given local address and port. + * + * @param address The address to bind to; the InetAddress is either + * an IPv4 or IPv6 address. + * @throws IOException If binding fails; for example, if the port + * in the given InetSocketAddress is privileged, and the current + * process has insufficient privileges. */ - static native void connect(PlainSocketImpl socket, InetAddress addr, - int port) throws IOException; - + public void bind(InetSocketAddress address) throws IOException + { + InetAddress addr = address.getAddress(); + if (addr instanceof Inet4Address) + { + bind (nfd.getNativeFD(), addr.getAddress(), address.getPort()); + } + else if (addr instanceof Inet6Address) + bind6 (nfd.getNativeFD(), addr.getAddress(), address.getPort()); + else + throw new SocketException ("unsupported address type"); + } + /** - * Binds to the specified port on the specified addr. Note that this addr - * must represent a local IP address. **** How bind to INADDR_ANY? **** - * - * @param socket the socket object - * @param addr the address to bind to - * @param port the port number to bind to + * Native bind function for IPv4 addresses. The addr array must be + * exactly four bytes long. + * + * VMs without native support need not implement this. * - * @exception IOException If an error occurs + * @param fd The native file descriptor integer. + * @param addr The IPv4 address, in network byte order. + * @param port The port to bind to. + * @throws IOException */ - static native void bind(PlainSocketImpl socket, InetAddress addr, int port) + private static native void bind(int fd, byte[] addr, int port) throws IOException; - + /** - * Starts listening for connections on a socket. The queueLen parameter - * is how many pending connections will queue up waiting to be serviced - * before being accepted. If the queue of pending requests exceeds this - * number, additional connections will be refused. - * - * @param socket the socket object - * @param queueLen the length of the pending connection queue + * Native bind function for IPv6 addresses. The addr array must be + * exactly sixteen bytes long. * - * @exception IOException if an error occurs - */ - static native void listen(PlainSocketImpl socket, int queueLen) - throws IOException; - - /** - * Accepts a new connection on this socket. + * VMs without native support need not implement this. * - * @param socket the socket object - * @param impl the socket object to accept this connection. + * @param fd The native file descriptor integer. + * @param addr The IPv6 address, in network byte order. + * @param port The port to bind to. + * @throws IOException */ - static native void accept(PlainSocketImpl socket, SocketImpl impl) + private static native void bind6(int fd, byte[] addr, int port) throws IOException; /** - * Returns the number of bytes that the caller can read from this socket - * without blocking. - * - * @param socket the socket object - * - * @return the number of readable bytes before blocking - * - * @throws IOException If an error occurs - */ - static native int available(PlainSocketImpl socket) throws IOException; - - /** - * Closes the socket. This will cause any InputStream or OutputStream - * objects for this Socket to be closed as well. - * - *

- * Note that if the SO_LINGER option is set on this socket, then the - * operation could block. - *

+ * Listen on this socket for incoming connections. * - * @param socket the socket object - * - * @throws IOException if an error occurs + * @param backlog The backlog of connections. + * @throws IOException If listening fails. + * @see gnu.java.nio.VMChannel#accept() */ - static native void close(PlainSocketImpl socket) throws IOException; - + public void listen(int backlog) throws IOException + { + listen(nfd.getNativeFD(), backlog); + } + /** - * Internal method used by SocketInputStream for reading data from - * the connection. Reads up to len bytes of data into the buffer - * buf starting at offset bytes into the buffer. + * Native listen function. VMs without native support need not implement + * this. * - * @param socket the socket object - * - * @return the actual number of bytes read or -1 if end of stream. - * - * @throws IOException if an error occurs + * @param fd The file descriptor integer. + * @param backlog The listen backlog size. + * @throws IOException */ - static native int read(PlainSocketImpl socket, byte[] buf, int offset, - int len) throws IOException; + private static native void listen(int fd, int backlog) throws IOException; - /** - * Internal method used by SocketInputStream for reading data from - * the connection. Reads and returns one byte of data. - * - * @param socket the socket object - * - * @return read byte or -1 if end of stream. - * - * @throws IOException if an error occurs - */ - static int read(PlainSocketImpl socket) throws IOException + public void join(InetAddress group) throws IOException { - byte[] buf = new byte[1]; - if (read(socket, buf, 0, 1) > 0) - return buf[0] & 0xFF; + if (group instanceof Inet4Address) + join(nfd.getNativeFD(), group.getAddress()); + else if (group instanceof Inet6Address) + join6(nfd.getNativeFD(), group.getAddress()); else - return -1; + throw new IllegalArgumentException("unknown address type"); } + + private static native void join(int fd, byte[] addr) throws IOException; + + private static native void join6(int fd, byte[] addr) throws IOException; + + public void leave(InetAddress group) throws IOException + { + if (group instanceof Inet4Address) + leave(nfd.getNativeFD(), group.getAddress()); + else if (group instanceof Inet6Address) + leave6(nfd.getNativeFD(), group.getAddress()); + else + throw new IllegalArgumentException("unknown address type"); + } + + private static native void leave(int fd, byte[] addr) throws IOException; + + private static native void leave6(int fd, byte[] addr) throws IOException; - /** - * Internal method used by SocketOuputStream for writing data to - * the connection. Writes up to len bytes of data from the buffer - * buf starting at offset bytes into the buffer. - * - * @param socket the socket object - * @param buf the buffer to write to the stream - * @param offset the start offset in the buffer - * @param len the number of bytes to write - * - * @throws IOException if an error occurs - */ - static native void write(PlainSocketImpl socket, byte[] buf, int offset, - int len) throws IOException; - - /** - * Internal method used by SocketOuputStream for writing data to - * the connection. Writes exactly one byte to the socket. - * - * @param socket the socket object - * @param data the byte to write to the socket - * - * @throws IOException if an error occurs - */ - static void write(PlainSocketImpl socket, int data) + public void joinGroup(InetSocketAddress addr, NetworkInterface netif) throws IOException { - write(socket, new byte[]{ (byte) data }, 0, 1); + InetAddress address = addr.getAddress(); + + if (address instanceof Inet4Address) + joinGroup(nfd.getNativeFD(), address.getAddress(), + netif != null ? netif.getName() : null); + else if (address instanceof Inet6Address) + joinGroup6(nfd.getNativeFD(), address.getAddress(), + netif != null ? netif.getName() : null); + else + throw new IllegalArgumentException("unknown address type"); } - - /** - * Sets the input stream for this socket to the end of the stream. Any - * attempts to read more bytes from the stream will return an EOF. - * - * @param socket the socket object - * - * @throws IOException if I/O errors occur - */ - static native void shutdownInput(PlainSocketImpl socket) throws IOException; - - /** - * Disables the output stream for this socket. Any attempt to write more - * data to the socket will throw an IOException. - * - * @param socket the socket object - * - * @throws IOException if I/O errors occur - */ - static native void shutdownOutput(PlainSocketImpl socket) throws IOException; - - /** - * Connects to the remote socket address with a specified timeout. - * - * @param socket the socket object - * @param address the remote address to connect to - * @param timeout the timeout to use for this connect, 0 means infinite. - * - * @throws IOException if an error occurs - */ - static synchronized void connect(PlainSocketImpl socket, - SocketAddress address, int timeout) + + private static native void joinGroup(int fd, byte[] addr, String ifname) + throws IOException; + + private static native void joinGroup6(int fd, byte[] addr, String ifname) + throws IOException; + + public void leaveGroup(InetSocketAddress addr, NetworkInterface netif) throws IOException { - InetSocketAddress sockAddr = (InetSocketAddress) address; - InetAddress addr = sockAddr.getAddress(); - - if (addr == null) - throw new UnknownHostException(sockAddr.getHostName()); - - int port = sockAddr.getPort(); - - if (timeout < 0) - throw new IllegalArgumentException("negative timeout"); - - Object oldTimeoutObj = null; - try - { - oldTimeoutObj = getOption(socket, SocketOptions.SO_TIMEOUT); - setOption(socket, SocketOptions.SO_TIMEOUT, new Integer(timeout)); - connect(socket, addr, port); - } - finally - { - if (oldTimeoutObj != null) - setOption(socket, SocketOptions.SO_TIMEOUT, oldTimeoutObj); - } + InetAddress address = addr.getAddress(); + if (address instanceof Inet4Address) + leaveGroup(nfd.getNativeFD(), address.getAddress(), + netif != null ? netif.getName() : null); + else if (address instanceof Inet6Address) + leaveGroup6(nfd.getNativeFD(), address.getAddress(), + netif != null ? netif.getName() : null); + else + throw new IllegalArgumentException("unknown address type"); } - - /** - * Send one byte of urgent data over the socket. - * - * @param socket the socket object - * @param data the byte to send + + private static native void leaveGroup(int fd, byte[] addr, String ifname) + throws IOException; + + private static native void leaveGroup6(int fd, byte[] addr, String ifname) + throws IOException; + + + public void shutdownInput() throws IOException + { + shutdownInput(nfd.getNativeFD()); + } + + private static native void shutdownInput(int native_fd) throws IOException; + + public void shutdownOutput() throws IOException + { + shutdownOutput(nfd.getNativeFD()); + } + + private static native void shutdownOutput(int native_fd) throws IOException; + + public void sendUrgentData(int data) throws IOException + { + sendUrgentData(nfd.getNativeFD(), data); + } + + private static native void sendUrgentData(int natfive_fd, int data) throws IOException; + + public void close() throws IOException + { + nfd.close(); + } + + // Inner classes. + + /** + * Our wrapper for the native file descriptor. In this implementation, + * it is a simple wrapper around {@link VMChannel.State}, to simplify + * management of the native state. */ - static void sendUrgendData(PlainSocketImpl socket, int data) + public final class State { - throw new InternalError ("PlainSocketImpl::sendUrgentData not implemented"); + private VMChannel.State channelFd; + + State() + { + channelFd = null; + } + + public boolean isValid() + { + if (channelFd != null) + return channelFd.isValid(); + return false; + } + + public int getNativeFD() throws IOException + { + return channelFd.getNativeFD(); + } + + public void setChannelFD(final VMChannel.State nfd) throws IOException + { + if (this.channelFd != null && this.channelFd.isValid()) + throw new IOException("file descriptor already initialized"); + this.channelFd = nfd; + } + + public void close() throws IOException + { + if (channelFd == null) + throw new IOException("invalid file descriptor"); + channelFd.close(); + } + + protected void finalize() throws Throwable + { + try + { + if (isValid()) + close(); + } + finally + { + super.finalize(); + } + } } -} +} \ No newline at end of file Index: vm/reference/gnu/java/nio/VMChannel.java =================================================================== RCS file: /cvsroot/classpath/classpath/vm/reference/gnu/java/nio/VMChannel.java,v retrieving revision 1.1 diff -u -r1.1 VMChannel.java --- vm/reference/gnu/java/nio/VMChannel.java 14 May 2006 03:34:55 -0000 1.1 +++ vm/reference/gnu/java/nio/VMChannel.java 15 Sep 2006 00:48:14 -0000 @@ -39,13 +39,22 @@ package gnu.java.nio; import gnu.classpath.Configuration; +import gnu.classpath.Pointer; +import gnu.classpath.jdwp.exception.NotImplementedException; import gnu.java.net.PlainSocketImpl; import gnu.java.nio.PipeImpl.SinkChannelImpl; import gnu.java.nio.PipeImpl.SourceChannelImpl; -import gnu.java.nio.channels.FileChannelImpl; +import gnu.java.nio.FileChannelImpl; import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; /** * Native interface to support configuring of channel to run in a non-blocking @@ -54,33 +63,43 @@ * @author Michael Barker * */ -public class VMChannel +public final class VMChannel { - private final int fd; - - private VMChannel(int fd) - { - this.fd = fd; - } + /** + * Our reference implementation uses an integer to store the native + * file descriptor. Implementations without such support + */ + private final State nfd; - public static VMChannel getVMChannel(PlainSocketImpl socket) - { - return new VMChannel(socket.getNativeFD()); - } + private Kind kind; - public static VMChannel getVMChannel(SourceChannelImpl source) + public VMChannel() { - return new VMChannel(source.getNativeFD()); + // XXX consider adding security check here, so only Classpath + // code may create instances. + this.nfd = new State(); + kind = Kind.OTHER; } - public static VMChannel getVMChannel(SinkChannelImpl sink) + /** + * This constructor is used by the POSIX reference implementation; + * other virtual machines need not support it. + * + * Important: do not call this in library code that is + * not specific to Classpath's reference implementation. + * + * @param native_fd The native file descriptor integer. + * @throws IOException + */ + VMChannel(final int native_fd) throws IOException { - return new VMChannel(sink.getNativeFD()); + this(); + this.nfd.setNativeFD(native_fd); } - public static VMChannel getVMChannel(FileChannelImpl file) + public State getState() { - return new VMChannel(file.getNativeFD()); + return nfd; } static @@ -93,81 +112,151 @@ initIDs(); } + public static VMChannel getStdin() throws IOException + { + return new VMChannel(stdin_fd()); + } + + public static VMChannel getStdout() throws IOException + { + return new VMChannel(stdout_fd()); + } + + public static VMChannel getStderr() throws IOException + { + return new VMChannel(stderr_fd()); + } + + private static native int stdin_fd(); + private static native int stdout_fd(); + private static native int stderr_fd(); + /** * Set the file descriptor to have the required blocking * setting. * - * @param fd - * @param blocking + * @param blocking The blocking flag to set. */ - public native void setBlocking(int fd, boolean blocking); + public void setBlocking(boolean blocking) throws IOException + { + setBlocking(nfd.getNativeFD(), blocking); + } + + private static native void setBlocking(int fd, boolean blocking) + throws IOException; - public void setBlocking(boolean blocking) + public int available() throws IOException { - setBlocking(fd, blocking); + return available(nfd.getNativeFD()); } + private static native int available(int native_fd) throws IOException; /** * Reads a byte buffer directly using the supplied file descriptor. - * Assumes that the buffer is a DirectBuffer. * - * @param fd Native file descriptor to read from. * @param dst Direct Byte Buffer to read to. * @return Number of bytes read. * @throws IOException If an error occurs or dst is not a direct buffers. */ - native int read(int fd, ByteBuffer dst) - throws IOException; - public int read(ByteBuffer dst) throws IOException { - return read(fd, dst); + return read(nfd.getNativeFD(), dst); } + private static native int read(int fd, ByteBuffer dst) throws IOException; + + /** + * Read a single byte. + * + * @return The byte read, or -1 on end of file. + * @throws IOException + */ + public int read() throws IOException + { + return read(nfd.getNativeFD()); + } + + private static native int read(int fd) throws IOException; + /** * Reads into byte buffers directly using the supplied file descriptor. * Assumes that the buffer list contains DirectBuffers. Will perform a * scattering read. * - * @param fd Native file descriptor to read from. * @param dsts An array direct byte buffers. * @param offset Index of the first buffer to read to. * @param length The number of buffers to read to. * @return Number of bytes read. * @throws IOException If an error occurs or the dsts are not direct buffers. */ - native long readScattering(int fd, ByteBuffer[] dsts, int offset, int length) - throws IOException; - public long readScattering(ByteBuffer[] dsts, int offset, int length) throws IOException { if (offset + length > dsts.length) throw new IndexOutOfBoundsException("offset + length > dsts.length"); - return readScattering(fd, dsts, offset, length); + return readScattering(nfd.getNativeFD(), dsts, offset, length); } + private static native long readScattering(int fd, ByteBuffer[] dsts, + int offset, int length) + throws IOException; + + /** + * Receive a datagram on this channel, returning the host address + * that sent the datagram. + * + * @param dst Where to store the datagram. + * @return The host address that sent the datagram. + * @throws IOException + */ + public SocketAddress receive(ByteBuffer dst) throws IOException + { + if (kind != Kind.SOCK_DGRAM) + throw new SocketException("not a datagram socket"); + ByteBuffer hostPort = ByteBuffer.allocateDirect(18); + int hostlen = receive(nfd.getNativeFD(), dst, hostPort); + if (hostlen == 0) + return null; + if (hostlen == 4) // IPv4 + { + byte[] addr = new byte[4]; + hostPort.get(addr); + int port = hostPort.getShort() & 0xFFFF; + return new InetSocketAddress(Inet4Address.getByAddress(addr), port); + } + if (hostlen == 16) // IPv6 + { + byte[] addr = new byte[16]; + hostPort.get(addr); + int port = hostPort.getShort() & 0xFFFF; + return new InetSocketAddress(Inet6Address.getByAddress(addr), port); + } + + throw new SocketException("host address received with invalid length: " + + hostlen); + } + + private static native int receive (int fd, ByteBuffer dst, ByteBuffer address) + throws IOException; + /** * Writes from a direct byte bufer using the supplied file descriptor. * Assumes the buffer is a DirectBuffer. * - * @param fd - * @param src + * @param src The source buffer. * @return Number of bytes written. * @throws IOException */ - native int write(int fd, ByteBuffer src) - throws IOException; - - public int write(ByteBuffer src) - throws IOException + public int write(ByteBuffer src) throws IOException { - return write(fd, src); + return write(nfd.getNativeFD(), src); } + private native int write(int fd, ByteBuffer src) throws IOException; + /** * Writes from byte buffers directly using the supplied file descriptor. * Assumes the that buffer list constains DirectBuffers. Will perform @@ -180,18 +269,448 @@ * @return Number of bytes written. * @throws IOException */ - native long writeGathering(int fd, ByteBuffer[] srcs,