? gotk.class ? gotk.java ? io-nio-final.patch ? io-nio.patch ? io-nio2.patch ? lib/org/omg ? lib/org/relaxng ? lib/org/ietf/jgss/ChannelBinding.class ? lib/org/ietf/jgss/GSSContext.class ? lib/org/ietf/jgss/GSSCredential.class ? lib/org/ietf/jgss/GSSException.class ? lib/org/ietf/jgss/GSSManager.class ? lib/org/ietf/jgss/GSSName.class ? lib/org/ietf/jgss/MessageProp.class ? lib/org/ietf/jgss/MessagesBundle.properties ? lib/org/ietf/jgss/Oid.class ? lib/org/w3c/dom/Attr.class ? lib/org/w3c/dom/CDATASection.class ? lib/org/w3c/dom/CharacterData.class ? lib/org/w3c/dom/Comment.class ? lib/org/w3c/dom/DOMConfiguration.class ? lib/org/w3c/dom/DOMError.class ? lib/org/w3c/dom/DOMErrorHandler.class ? lib/org/w3c/dom/DOMException.class ? lib/org/w3c/dom/DOMImplementation.class ? lib/org/w3c/dom/DOMImplementationList.class ? lib/org/w3c/dom/DOMImplementationSource.class ? lib/org/w3c/dom/DOMLocator.class ? lib/org/w3c/dom/DOMStringList.class ? lib/org/w3c/dom/Document.class ? lib/org/w3c/dom/DocumentFragment.class ? lib/org/w3c/dom/DocumentType.class ? lib/org/w3c/dom/Element.class ? lib/org/w3c/dom/Entity.class ? lib/org/w3c/dom/EntityReference.class ? lib/org/w3c/dom/NameList.class ? lib/org/w3c/dom/NamedNodeMap.class ? lib/org/w3c/dom/Node.class ? lib/org/w3c/dom/NodeList.class ? lib/org/w3c/dom/Notation.class ? lib/org/w3c/dom/ProcessingInstruction.class ? lib/org/w3c/dom/Text.class ? lib/org/w3c/dom/TypeInfo.class ? lib/org/w3c/dom/UserDataHandler.class ? lib/org/w3c/dom/bootstrap ? lib/org/w3c/dom/css ? lib/org/w3c/dom/events ? lib/org/w3c/dom/html2 ? lib/org/w3c/dom/ls ? lib/org/w3c/dom/ranges ? lib/org/w3c/dom/stylesheets ? lib/org/w3c/dom/traversal ? lib/org/w3c/dom/views ? lib/org/w3c/dom/xpath ? lib/org/xml/sax/AttributeList.class ? lib/org/xml/sax/Attributes.class ? lib/org/xml/sax/ContentHandler.class ? lib/org/xml/sax/DTDHandler.class ? lib/org/xml/sax/DocumentHandler.class ? lib/org/xml/sax/EntityResolver.class ? lib/org/xml/sax/ErrorHandler.class ? lib/org/xml/sax/HandlerBase.class ? lib/org/xml/sax/InputSource.class ? lib/org/xml/sax/Locator.class ? lib/org/xml/sax/Parser.class ? lib/org/xml/sax/SAXException.class ? lib/org/xml/sax/SAXNotRecognizedException.class ? lib/org/xml/sax/SAXNotSupportedException.class ? lib/org/xml/sax/SAXParseException.class ? lib/org/xml/sax/XMLFilter.class ? lib/org/xml/sax/XMLReader.class ? lib/org/xml/sax/ext ? lib/org/xml/sax/helpers Index: ChangeLog =================================================================== RCS file: /cvsroot/classpath/classpath/ChangeLog,v retrieving revision 1.8550 diff -u -r1.8550 ChangeLog --- ChangeLog 16 Sep 2006 17:54:42 -0000 1.8550 +++ ChangeLog 17 Sep 2006 06:17:09 -0000 @@ -1,3 +1,329 @@ +<<<<<<< ChangeLog +2006-09-16 Casey Marshall + + * NEWS: updated. + * configure.ac (AC_CHECK_HEADERS): check for `sys/event.h'. + (AC_CHECK_FUNCS): add checks for readv, writev, getifaddrs, + kqueue, and kevent. + (HAVE_INET6): define if IPv6 is supported. + * gnu/java/net/PlainDatagramSocketImpl.java (channel): new field. + (native_fd): removed. + (impl): new field. + (): throw IOException; initialize fields. + (finalize): removed. + (getNativeFD): removed. + (bind): use `PlainSocketImpl.bind.' + (create): use `PlainSocketImpl.initSocket.' + (disconnect): use `PlainSocketImpl.disconnect.' + (getLocalPort): new method. + (send): use `VMChannel.send.' + (receive): use `VMChannel.receive.' + (setOption): use `PlainSocketImpl.setOption.' + (getOption): use `PlainSocketImpl.getOption.' + (close): use `VMChannel.State.close.' + (join): use `PlainSocketImpl.join.' + (leave): use `PlainSocketImpl.leave.' + (joinGroup, leaveGroup): implemented. + * gnu/java/net/PlainSocketImpl.java: make non-final. + (native_fd): removed. + (impl): new field. + (channel): new field. + (): initialize `impl.' + (finalize, getNativeFD): removed. + (setOption): use `PlainSocketImpl.setOption.' + (getOption): use `PlainSocketImpl.getOption.' + (shutdownInput): use `PlainSocketImpl.shutdownInput.' + (shutdownOutput): use `PlainSocketImpl.shutdownOutput.' + (create): create `channel,' initialize `impl's native state. + (connect): use `connect(SocketAddress, int).' + (connect): use `SocketChannelImpl.connect;' initialize `address' + and `port.' + (bind): use `VMPlainSocketImpl.bind.' + (listen): use `VMPlainSocketImpl.listen.' + (accept): use `SocketChannelImpl.accept.' + (available): use `VMChannel.available.' + (close): use `PlainSocketImpl.close.' + (sendUrgentData): use `PlainSocketImpl.sendUrgentData.' + (getVMChannel, getInetAddress, getLocalPort, getLocalAddress, + getPort): new methods. + (SocketInputStream.read): use `VMChannel.read.' + (SocketInputStream.read): use `SocketChannel.read.' + (SocketOutputStream.write): use `VMChannel.write.' + (SocketOutputStream.write): use `SocketChannel.write.' + * gnu/java/nio/DatagramChannelImpl.java: implement VMChannel. + (channel): new field. + (): initialize `channel.' + (implCloseSelectableChannel): use `VMChannel.close.' + (implConfigureBlocking): use `VMChannel.setBlocking.' + (connect): use `VMChannel.connect.' + (disconnect): use `VMChannel.disconnect.' + (isConnected): use `VMChannel.getPeerAddress.' + (write): use `VMChannel.write.' + (write): use `VMChannel.writeGathering.' + (read): use `VMChannel.read.' + (read): use `VMChannel.readScattering.' + (receive): use `VMChannel.receive.' + (send): use `VMChannel.send.' + (getVMChannel): new method. + * gnu/java/nio/DatagramChannelSelectionKey.java (getNativeFD): + access native FD through VMChannel.State. + * gnu/java/nio/FileChannelImpl.java: moved from + gnu/java/nio/channels/FileChannelImpl.java. + * gnu/java/nio/FileLockImpl.java: fix imports. + * gnu/java/nio/KqueueSelectionKeyImpl.java: new file. + * gnu/java/nio/KqueueSelectorImpl.java: new file. + * gnu/java/nio/NIOSocket.java (impl): removed. + (channel): new field. + (): init superclass with a `NIOSocketImpl;' init `channel.' + (getPlainSocketImpl, setChannel): removed. + (isConnected): new method. + * gnu/java/nio/NIOSocketImpl.java: new file. + * gnu/java/nio/PipeImpl.java (SourceChannelImpl): implement + `VMChannelOwner.' + (SourceChannelImpl.native_fd): removed. + (SourceChannelImpl.): init with a `VMChannel.' + (SourceChannelImpl.getNativeFD): removed. + (SourceChannelImpl.getVMChannel): new method. + (SourceChannelImpl.implCloseSelectableChannel): implement. + (SinkChannelImpl): implement `VMChannelOwner.' + (SinkChannelImpl.native_fd): removed. + (SinkChannelImpl.): init with a `VMChannel.' + (SinkChannelImpl.implCloseSelectableChannel): implement. + (SinkChannelImpl.getNativeFD): removed. + (SinkChannelImpl.getVMChannel): new method. + * gnu/java/nio/SelectionKeyImpl.java (getNativeFD): mark + deprecated. + * gnu/java/nio/SelectorProviderImpl.java (SELECTOR_IMPL_KQUEUE, + SELECTOR_IMPL_EPOLL, SELECTOR_IMPL): new constants. + (openSelector): return kqueue selector if available. + * gnu/java/nio/ServerSocketChannelImpl.java: implement + `VMChannelOwner.' + (channel): new field. + (): init `channel.' + (finalizer): check if the `VMChannel.State' is valid. + (implCloseSelectableChannel): use `VMChannel.close.' + (implConfigureBlocking): use `VMChannel.setBlocking.' + (accept): use `VMChannel.accept.' + (getVMChannel): new method. + * gnu/java/nio/ServerSocketChannelSelectionKey.java (getNativeFD): + access native FD through `VMChannel.State.' + * gnu/java/nio/SocketChannelImpl.java: implement `VMChannelOwner.' + (impl): removed. + (channel, connected, connectAddress): new field. + (): new constructors. + (getPlainSocketImpl): removed. + (implCloseSelectableChannel): use `VMChannel.close.' + (implConfigureBlocking): use `VMChannel.setBlocking.' + (connect): use `connect(SocketAddress,int).' + (connect): use `VMChannel.connect.' + (finishConnect): don't use a selector. + (isConnected): use `VMChannel.getPeerAddress.' + (read): use `VMChannel.read.' + (read): use `VMChannel.readScattering.' + (write): use `VMChannel.write.' + (write): use `VMChannel.writeGathering.' + (getVMChannel): new method. + * gnu/java/nio/SocketChannelSelectionKey.java (getNativeFD): get + native FD from `VMChannel.State.' + * gnu/java/nio/SocketChannelSelectionKeyImpl.java (getNativeFD): + get native FD from `VMChannel.State.' + * gnu/java/nio/VMChannelOwner.java: new file. + * gnu/java/nio/channels/FileChannelImpl.java: removed. + * include/Makefile.am: generate `gnu_java_nio_FileChannelImpl.h' + and `gnu_java_nio_KqueueSelectorImpl.h;' don't generate + `gnu_java_nio_channels_FileChannelImpl.h.' + * include/gnu_java_net_VMPlainSocketImpl.h: regenerated. + * include/gnu_java_nio_FileChannelImpl.h: new file. + * include/gnu_java_nio_KqueueSelectorImpl.h: new file. + * include/gnu_java_nio_VMChannel.h: regenerated. + * include/gnu_java_nio_VMPipe.h: regenerated. + * include/java_net_VMNetworkInterface.h: regenerated. + * java/io/FileDescriptor.java: fix imports. + * java/io/FileInputStream.java (): handle exceptions. + (read): wrap the destination arary. + * java/io/FileOutputStream.java (): handle exceptions. + (write): wrap the source array. + * java/io/RandomAccessFile.java (): handle exceptions. + * java/net/DatagramSocket.java (): handle exceptions. + (receive): handle length/port setting. + (connect): bind to any address/port if the argument is null. + * java/net/NetworkInterface.java (name, inetAddress): removed. + (netif): new field. + (): make private. + (getName): return `netif.name.' + (getInetAddresses): access `netif.addresses.' + (getDisplayName): return `netif.name.' + (getByName, getByAddress): handle changes to `VMNetworkInterface.' + (condense): removed. + (getNetworkInterfaces): handle changes to `VMNetworkInterface.' + (equals): compare `netif' fields. + (hashCode): get hash codes from `netif.' + (toString): use a StringBuffer. + * java/net/ServerSocket.java (close): don't set `impl' to null. + (isClosed): use `VMChannel.State.isClosed.' + * java/net/Socket.java (getLocalAddress): don't use `getOption' if + the `SocketImpl' is a `PlainSocketImpl.' + (close): just close the `impl.' + (toString): use `super.toString' in the value we return. + (isConnected): just access `impl,' not `getImpl.' + (isBound): use `PlainSocketImpl' methods if we can. + (isClosed): look at `VMChannel.State.' + * native/jni/classpath/jcl.c (JNI_OnLoad): new function. + (JCL_NewRawDataObject): don't initialize cached fields here; throw + an exception if they were not. + (JCL_GetRawData): throw an exception if cached fields weren't + created. + * native/jni/java-lang/java_lang_VMProcess.c: handle + FileChannelImpl move. + * native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c + (IO_EXCEPTION, SOCKET_EXCEPTION, BIND_EXCEPTION, + THROW_NO_NETWORK): new macros. + (Java_gnu_java_net_VMPlainSocketImpl_bind): reipmlemented. + (Java_gnu_java_net_VMPlainSocketImpl_bind6): new function. + (Java_gnu_java_net_VMPlainSocketImpl_listen): reimplemented. + (java_sockopt): new enum. + (Java_gnu_java_net_VMPlainSocketImpl_setOption): reimplemented. + (Java_gnu_java_net_VMPlainSocketImpl_getOption): reimplemented. + (Java_gnu_java_net_VMPlainSocketImpl_shutdownInput): + reimplemented. + (Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput): + reimplemented. + (Java_gnu_java_net_VMPlainSocketImpl_sendUrgentData): new + function. + (Java_gnu_java_net_VMPlainSocketImpl_join): new function. + (Java_gnu_java_net_VMPlainSocketImpl_join6): new function. + (Java_gnu_java_net_VMPlainSocketImpl_read): removed. + (Java_gnu_java_net_VMPlainSocketImpl_leave): new function. + (Java_gnu_java_net_VMPlainSocketImpl_leave6): new function. + (Java_gnu_java_net_VMPlainSocketImpl_joinGroup): new function. + (Java_gnu_java_net_VMPlainSocketImpl_write): removed. + (Java_gnu_java_net_VMPlainSocketImpl_joinGroup6): new function. + (Java_gnu_java_net_VMPlainSocketImpl_leaveGroup): new function. + (Java_gnu_java_net_VMPlainSocketImpl_leaveGroup6): new function. + (getif_address): new function. + (getif_index): new function. + * native/jni/java-net/java_net_VMNetworkInterface.c + (java_net_VMNetworkInterface_init, + java_net_VMNetworkInterface_addAddress): new file-scope globals. + (Java_java_net_VMNetworkInterface_initIds): new function. + (struct netif_entry): new struct. + (free_netif_list): new function. + (Java_java_net_VMNetworkInterface_getInterfaces): removed. + (Java_java_net_VMNetworkInterface_getVMInterfaces): new function. + * native/jni/java-nio/Makefile.am (libjavanio_la_SOURCES): remove + gnu_java_nio_channels_FileChannelImpl.c, add + gnu_java_nio_KqueueSelectorImpl.c. + * native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c: new file. + * native/jni/java-nio/gnu_java_nio_VMChannel.c + (INTERRUPTED_IO_EXCEPTION, SOCKET_TIMEOUT_EXCEPTION, ALIGN_UP, + ALIGN_DOWN): new macros. + (JCL_init_buffer): get the address through GetDirectBufferAddress + if possible. + (Java_gnu_java_nio_VMChannel_stdin_1fd, + Java_gnu_java_nio_VMChannel_stdout_1fd, + Java_gnu_java_nio_VMChannel_stderr_1fd): new functions. + (Java_gnu_java_nio_VMChannel_setBlocking): fix setting blocking + value. + (Java_gnu_java_nio_VMChannel_read): renamed... + (Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2): to + this; handle interrupted IO; add HAVE_READ check. + (Java_gnu_java_nio_VMChannel_write): renamed... + (Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2): to + this; handle zero-length write; add HAVE_WRITE check. + (Java_gnu_java_nio_VMChannel_receive): new function. + (Java_gnu_java_nio_VMChannel_send): new function. + (Java_gnu_java_nio_VMChannel_send6): new function. + (Java_gnu_java_nio_VMChannel_read__I): new function. + (Java_gnu_java_nio_VMChannel_write__II): new function. + (Java_gnu_java_nio_VMChannel_socket): new function. + (Java_gnu_java_nio_VMChannel_connect): new function. + (Java_gnu_java_nio_VMChannel_connect6): new function. + (Java_gnu_java_nio_VMChannel_getsockname): new function. + (Java_gnu_java_nio_VMChannel_getpeername): new function. + (Java_gnu_java_nio_VMChannel_accept): new function. + (Java_gnu_java_nio_VMChannel_disconnect): new function. + (Java_gnu_java_nio_VMChannel_close): new function. + (Java_gnu_java_nio_VMChannel_available): new function. + (FileChannel_mode): new enum. + (Java_gnu_java_nio_VMChannel_open): new function. + (Java_gnu_java_nio_VMChannel_position): new function. + (Java_gnu_java_nio_VMChannel_seek): new function. + (Java_gnu_java_nio_VMChannel_truncate): new funciton. + (Java_gnu_java_nio_VMChannel_lock): new function. + (Java_gnu_java_nio_VMChannel_unlock): new function. + (Java_gnu_java_nio_VMChannel_size): new function. + (Java_gnu_java_nio_VMChannel_map): new function. + (Java_gnu_java_nio_VMChannel_flush): new function. + * native/jni/java-nio/gnu_java_nio_VMPipe.c + (Java_gnu_java_nio_VMPipe_init): removed. + (Java_gnu_java_nio_VMPipe_pipe0): new function. + * native/jni/java-nio/javanio.c: new file. + * native/jni/java-nio/javanio.h: new file. + * native/jni/native-lib/cpnet.c (cpnet_getHostByName): fix for + systems without `gethostbyname_r.' + * vm/reference/gnu/java/net/VMPlainSocketImpl.java (nfd): new + field. + (, ): new constructors. + (setOption, getOption): make instance methods; defer to native + implementation. + (connect): removed. + (bind): make an instance method; defer to native methods. + (accept): removed. + (available): removed. + (listen): make an instance method; defer to native method. + (read): removed. + (join, leave): new methods. + (write): removed. + (joinGroup, leaveGroup): new methods. + (shutdownInput, shutdownOutput): make instance methods. + (sendUrgentData): removed. + (State): new class. + * vm/reference/gnu/java/nio/VMChannel.java: make final. + (fd): removed. + (nfd): new field. + (): new, public constructors. + (getVMChannel): methods removed. + (getState, getStdin, getStdout, getStderr, stdin_fd, stdout_fd, + stderr_fd): new methods. + (setBlocking): make an instance method. + (available): new method. + (read): get native fd from `nfd.' + (read): new single-byte read method. + (readScattering): get native fd from `nfd.' + (receive): new method. + (write, writeGathering): get native fd from `nfd.' + (send): new method. + (write): new single-byte write method. + (initSocket): new method. + (connect): new method. + (disconnect): new method. + (getLocalAddress): new method. + (getPeerAddress): new method. + (accept): new method. + (openFile): new method. + (position): new method. + (seek): new method. + (truncate): new method. + (lock): new method. + (unlock): new method. + (size): new method. + (map): new method. + (flush): new method. + (close): new method. + (State): new class. + (Kind): new class. + * vm/reference/gnu/java/nio/VMPipe.java (init): removed. + (pipe, pipe0): new method. + * vm/reference/java/net/VMNetworkInterface.java (name, addresses): + new fields. + (): call `initIds.' + (initIds): new method. + (getInterfaces): removed. + (getVMInterfaces): new method. + (addAddress): new method. + * vm/reference/java/nio/channels/VMChannels.java: fix imports. + +======= 2006-09-16 Chris Burdess Fixes PR 28572. @@ -9,6 +335,7 @@ Fixes PR 27293. * gnu/xml/dom/DomNode.java: Increment length of node during insert. +>>>>>>> 1.8550 2006-09-14 Michael Koch * include/gnu_java_awt_peer_gtk_CairoGraphics2D.h: Recreated. Index: NEWS =================================================================== RCS file: /cvsroot/classpath/classpath/NEWS,v retrieving revision 1.167 diff -u -r1.167 NEWS --- NEWS 8 Sep 2006 08:59:57 -0000 1.167 +++ NEWS 17 Sep 2006 06:17:10 -0000 @@ -17,6 +17,26 @@ vm/reference/gnu/classpath/VMStackWalker.java. VMs are encouraged to provide a more efficient implementation. * Added aton method to vm/reference/java/net/VMInetAddress.java. +* NetworkInterface has been implemented for systems that provide the + `getifaddrs' function. +* A java.nio.channels.Selector implementation based on the + kqueue/kevent notification mechanism has been added for Mac OS X and + BSD systems. +* java.nio has been refactored to support more non-blocking operations + natively. Blocking IO classes have been refactored to call + non-blocking classes. Non-blocking accepts, connects, and + scatter-gather IO should now be better supported. + +Runtime interface changes: + +* java.net.VMNetworkInterface and java.net.NetworkInterface have been + updated to keep native-modified state in the former, and to simplify + the native code in our reference implementation. +* gnu.java.nio.VMChannel has been expanded to better support native + non-blocking IO. Most native state data (such as file descriptor + integers) has been abstracted away into private state in the runtime + interface. +* gnu.java.nio.VMPipe has been similarly changed. New in release 0.92 (Aug 9, 2006) 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 17 Sep 2006 06:17:10 -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/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 17 Sep 2006 06:17:11 -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.leave(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 17 Sep 2006 06:17:11 -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 17 Sep 2006 06:17:11 -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 17 Sep 2006 06:17:11 -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/FileChannelImpl.java =================================================================== RCS file: gnu/java/nio/FileChannelImpl.java diff -N gnu/java/nio/FileChannelImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/nio/FileChannelImpl.java 17 Sep 2006 06:17:11 -0000 @@ -0,0 +1,572 @@ +/* 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; + +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 final FileChannelImpl in; + public static final FileChannelImpl out; + public static final FileChannelImpl err; + + //private static native void init(); + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javanio"); + } + + //init(); + + FileChannelImpl ch = null; + try + { + ch = new FileChannelImpl(VMChannel.getStdin(), READ); + } + catch (IOException ioe) + { + throw new Error(ioe); + } + in = ch; + + ch = null; + try + { + ch = new FileChannelImpl(VMChannel.getStdout(), WRITE); + } + catch (IOException ioe) + { + throw new Error(ioe); + } + out = ch; + + ch = null; + try + { + ch = new FileChannelImpl(VMChannel.getStderr(), WRITE); + } + catch (IOException ioe) + { + throw new Error(ioe); + } + err = ch; + } + + /** + * This is the actual native file descriptor value + */ + 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 IOException + { + return new FileChannelImpl(file, mode); + } + + private FileChannelImpl(File file, int mode) + throws IOException + { + String path = file.getPath(); + description = path; + this.mode = mode; + this.ch = new VMChannel(); + ch.openFile(path, mode); + + // 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 (VMChannel ch, int mode) + { + this.mode = mode; + this.description = "descriptor(" + ch.getState() + ")"; + this.ch = ch; + } + + public int available() throws IOException + { + return ch.available(); + } + + private long implPosition() throws IOException + { + return ch.position(); + } + + private void seek(long newPosition) throws IOException + { + ch.seek(newPosition); + } + + private void implTruncate(long size) throws IOException + { + ch.truncate(size); + } + + public void unlock(long pos, long len) throws IOException + { + ch.unlock(pos, len); + } + + public long size () throws IOException + { + return ch.size(); + } + + protected void implCloseChannel() throws IOException + { + ch.close(); + } + + /** + * Makes sure the Channel is properly closed. + */ + protected void finalize() throws IOException + { + if (ch.getState().isValid()) + close(); + } + + public int read (ByteBuffer dst) throws IOException + { + 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 int read() throws IOException + { + return ch.read(); + } + + 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 void write (int b) throws IOException + { + ch.write(b); + } + + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + return ch.writeGathering(srcs, offset, length); + } + + 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 ch.map(nmode, position, (int) size); + } + + /** + * msync with the disk + */ + public void force (boolean metaData) throws IOException + { + if (!isOpen ()) + throw new ClosedChannelException (); + + ch.flush(metaData); + } + + // 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 = ch.lock(position, size, shared, false); + completed = true; + return (lockable + ? new FileLockImpl(this, position, size, shared) + : null); + } + finally + { + end(completed); + } + } + + public FileLock lock (long position, long size, boolean shared) + throws IOException + { + lockCheck(position, size, shared); + + boolean completed = false; + try + { + boolean lockable = ch.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 (super.toString() + + "[ fd: " + ch.getState() + + "; mode: " + Integer.toOctalString(mode) + + "; " + description + " ]"); + } + + /** + * @return The native file descriptor. + * / + public int getNativeFD() + { + return fd; + }*/ +} 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 17 Sep 2006 06:17:11 -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/KqueueSelectionKeyImpl.java =================================================================== RCS file: gnu/java/nio/KqueueSelectionKeyImpl.java diff -N gnu/java/nio/KqueueSelectionKeyImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/nio/KqueueSelectionKeyImpl.java 17 Sep 2006 06:17:12 -0000 @@ -0,0 +1,175 @@ +/* KqueueSelectionKeyImpl.java -- selection key for kqueue/kevent. + Copyright (C) 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; + + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class KqueueSelectionKeyImpl extends SelectionKey +{ + int interestOps; + int readyOps; + ByteBuffer nstate; + boolean valid; + int key; + boolean readEverEnabled = false; + boolean writeEverEnabled = false; + + /** The selector we were created for. */ + private final KqueueSelectorImpl selector; + + /** The channel we are attached to. */ + private final SelectableChannel channel; + + private final VMChannelOwner natChannel; + + public KqueueSelectionKeyImpl(KqueueSelectorImpl selector, + SelectableChannel channel) + { + this.selector = selector; + this.channel = channel; + natChannel = (VMChannelOwner) channel; + interestOps = 0; + readyOps = 0; + valid = true; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#cancel() + */ + //@Override + public void cancel() + { + selector.doCancel(this); + valid = false; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#channel() + */ + //@Override + public SelectableChannel channel() + { + return channel; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#interestOps() + */ + //@Override + public int interestOps() + { + return interestOps; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#interestOps(int) + */ + //@Override + public SelectionKey interestOps(int ops) + { + if (!isValid()) + throw new IllegalStateException(); + if ((ops & ~channel.validOps()) != 0) + throw new IllegalArgumentException(); + this.interestOps = ops; + try + { + selector.updateOps(this, + natChannel.getVMChannel().getState().getNativeFD(), + false); + } + catch (IOException ioe) + { + throw new IllegalStateException("channel is invalid"); + } + return this; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#isValid() + */ + //@Override + public boolean isValid() + { + return valid && selector.isOpen(); + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#readyOps() + */ + //@Override + public int readyOps() + { + return readyOps; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#selector() + */ + //@Override + public Selector selector() + { + return selector; + } + + public String toString() + { + if (!isValid()) + return super.toString() + " [ <> ]"; + return super.toString() + " [ interest ops: {" + + ((interestOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "") + + ((interestOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "") + + ((interestOps & OP_READ) != 0 ? " OP_READ" : "") + + ((interestOps & OP_WRITE) != 0 ? " OP_WRITE" : "") + + " }; ready ops: {" + + ((readyOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "") + + ((readyOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "") + + ((readyOps & OP_READ) != 0 ? " OP_READ" : "") + + ((readyOps & OP_WRITE) != 0 ? " OP_WRITE" : "") + + " } ]"; + } +} Index: gnu/java/nio/KqueueSelectorImpl.java =================================================================== RCS file: gnu/java/nio/KqueueSelectorImpl.java diff -N gnu/java/nio/KqueueSelectorImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/nio/KqueueSelectorImpl.java 17 Sep 2006 06:17:12 -0000 @@ -0,0 +1,434 @@ +/* KqueueSelectorImpl.java -- Selector for systems with kqueue event notification. + Copyright (C) 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; + + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * A {@link Selector} implementation that uses the kqueue + * event notification facility. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class KqueueSelectorImpl extends AbstractSelector +{ + private static final int sizeof_struct_kevent; + + static + { + try + { + System.loadLibrary("javanio"); + } + catch (Exception x) + { + x.printStackTrace(); + } + + if (kqueue_supported ()) + sizeof_struct_kevent = sizeof_struct_kevent(); + else + sizeof_struct_kevent = -1; + } + + /** + * Tell if kqueue-based selectors are supported on this system. + * + * @return True if this system has kqueue support, and support for it was + * compiled in to Classpath. + */ + public static native boolean kqueue_supported(); + + /* Our native file descriptor. */ + private int kq; + + private HashMap/**/ keys; + private HashSet/**/ selected; + private HashSet/**/ cancelled; + private Thread blockedThread; + + public KqueueSelectorImpl(SelectorProvider provider) throws IOException + { + super(provider); + kq = implOpen(); + keys = new HashMap/**/(); + cancelled = new HashSet(); + } + + protected void implCloseSelector() throws IOException + { + implClose(kq); + kq = -1; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#keys() + */ + public Set keys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return new HashSet(keys.values()); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select() + */ + public int select() throws IOException + { + return doSelect(-1); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select(long) + */ + public int select(long timeout) throws IOException + { + if (timeout == 0) + timeout = -1; + return doSelect(timeout); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectedKeys() + */ + public Set selectedKeys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return selected; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectNow() + */ + public int selectNow() throws IOException + { + return doSelect(0); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#wakeup() + */ + public Selector wakeup() + { + if (blockedThread != null) + blockedThread.interrupt(); + return this; + } + + synchronized int doSelect(long timeout) throws IOException + { + // FIXME -- I'm unclear on how we should synchronize this; and how to + // handle cancelled keys. + for (Iterator it = cancelled.iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + updateOps(key, 0, true); + } + int events_size = 0; + for (Iterator it = keys.values().iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + if ((key.interestOps & SelectionKey.OP_ACCEPT) != 0 + || (key.interestOps & SelectionKey.OP_READ) != 0) + key.readEverEnabled = true; + if ((key.interestOps & SelectionKey.OP_CONNECT) != 0 + || (key.interestOps & SelectionKey.OP_WRITE) != 0) + key.writeEverEnabled = true; + + if (key.readEverEnabled) + events_size += sizeof_struct_kevent; + if (key.writeEverEnabled) + events_size += sizeof_struct_kevent; + } + + // We handle native events a little strangely here; per selection key, + // we allocate enough space for two struct kevents, the first in the + // list will be our EVFILT_READ filter, the second our EVFILT_WRITE + // one. If only one of the two needs enabling, though, we don't want + // to pass the other to kevent, because that would result in spurious + // events. We can break down our handling as follows: + // + // - READ enabled, WRITE never enabled. We pass only the first structure + // to kevent. + // - WRITE enabled, READ never enabled. Likewise, but only pass the + // second structure. + // - READ and WRITE enabled. Pass both. + // - READ enabled, WRITE enabled in the past. Pass both, with the + // first structure's flag set to EV_ADD or EV_ENABLE, and the second + // with EV_DISABLE. It seems OK to keep sending events with the + // EV_DISABLE flag. + // - WRITE enabled, READ enabled in the past. Likewise, but flipped. + // + // We handle these states with the readEverEnabled and writeEverEnabled + // flags of selection keys; they start off as false, and become true + // the first time we select() with READ or WRITE enabled. They never + // become false. + ByteBuffer events = ByteBuffer.allocateDirect(events_size); + + for (Iterator it = keys.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) e.getValue(); + + if (key.readEverEnabled) + events.put((ByteBuffer) key.nstate.duplicate().limit + (sizeof_struct_kevent)); + if (key.writeEverEnabled) + events.put((ByteBuffer) key.nstate.duplicate().position + (sizeof_struct_kevent).limit(2 * sizeof_struct_kevent)); + } + events.rewind(); + + //System.out.println("dump of keys to select:"); + //dump_selection_keys(events.duplicate()); + + blockedThread = Thread.currentThread(); + if (blockedThread.isInterrupted()) + timeout = 0; + final int n = kevent(kq, events, events_size / sizeof_struct_kevent, + timeout); + Thread.interrupted(); + + //System.out.println("dump of keys selected:"); + //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * sizeof_struct_kevent)); + + selected = new HashSet/**/(n); + int x = 0; + for (int i = 0; i < n; i++) + { + events.position(x).limit(x + sizeof_struct_kevent); + x += sizeof_struct_kevent; + int y = fetch_key(events.slice()); + KqueueSelectionKeyImpl key = + (KqueueSelectionKeyImpl) keys.get(new Integer(y)); + key.readyOps = ready_ops(events.slice(), key.interestOps); + selected.add(key); + } + for (Iterator it = cancelled.iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + keys.remove(new Integer(key.key)); + it.remove(); + } + + return selected.size(); + } + + protected SelectionKey register(AbstractSelectableChannel channel, + int interestOps, + Object attachment) + { + int native_fd = -1; + try + { + if (channel instanceof VMChannelOwner) + native_fd = ((VMChannelOwner) channel).getVMChannel() + .getState().getNativeFD(); + else + throw new IllegalArgumentException("cannot handle channel type " + + channel.getClass().getName()); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("channel is closed or invalid"); + } + + KqueueSelectionKeyImpl result = new KqueueSelectionKeyImpl(this, channel); + result.interestOps = interestOps; + result.attach(attachment); + int k = System.identityHashCode(result); + while (keys.containsKey(new Integer(k))) + k++; + result.key = k; + keys.put(new Integer(k), result); + result.nstate = ByteBuffer.allocateDirect(2 * sizeof_struct_kevent); + updateOps(result, native_fd, false); + return result; + } + + synchronized void updateOps(KqueueSelectionKeyImpl key) + { + updateOps(key, 0, false); + } + + synchronized void updateOps(KqueueSelectionKeyImpl key, int fd, boolean delete) + { + //System.out.println(">> updating kqueue selection key:"); + //dump_selection_keys(key.nstate.duplicate()); + //System.out.println("<<"); + kevent_set(key.nstate, fd, key.interestOps, key.key, delete); + //System.out.println(">> updated kqueue selection key:"); + //dump_selection_keys(key.nstate.duplicate()); + //System.out.println("<<"); + } + + synchronized void doCancel(KqueueSelectionKeyImpl key) + { + cancelled.add(key); + } + + private void dump_selection_keys(ByteBuffer keys) + { + // WARNING! This method is not guaranteed to be portable! This works + // on darwin/x86, but the sizeof and offsetof these fields may be + // different on other platforms! + int i = 0; + keys.order(ByteOrder.nativeOrder()); + while (keys.hasRemaining()) + { + System.out.println("struct kevent { ident: " + + Integer.toString(keys.getInt()) + + " filter: " + + Integer.toHexString(keys.getShort() & 0xFFFF) + + " flags: " + + Integer.toHexString(keys.getShort() & 0xFFFF) + + " fflags: " + + Integer.toHexString(keys.getInt()) + + " data: " + + Integer.toHexString(keys.getInt()) + + " udata: " + + Integer.toHexString(keys.getInt()) + + " }"); + } + } + + /** + * Return the size of a struct kevent on this system. + * + * @return The size of struct kevent. + */ + private static native int sizeof_struct_kevent(); + + /** + * Opens a kqueue descriptor. + * + * @return The new kqueue descriptor. + * @throws IOException If opening fails. + */ + private static native int implOpen() throws IOException; + + /** + * Closes the kqueue file descriptor. + * + * @param kq The kqueue file descriptor. + * @throws IOException + */ + private static native void implClose(int kq) throws IOException; + + /** + * Initialize the specified native state for the given interest ops. + * + * @param nstate The native state structures; in this buffer should be + * the struct kevents created for a key. + * @param fd The file descriptor. If 0, the native FD is unmodified. + * @param interestOps The operations to enable. + * @param key A unique key that will reference the associated key later. + * @param delete Set to true if this event should be deleted from the + * kqueue (if false, this event is added/updated). + */ + private static native void kevent_set(ByteBuffer nstate, int fd, int interestOps, + int key, boolean delete); + + /** + * Poll for events. The source events are stored in events, + * which is also where polled events will be placed. + * + * @param events The events to poll. This buffer is also the destination + * for events read from the queue. + * @param nevents The number of events to poll (that is, the number of + * events in the events buffer). + * @param timeout The timeout. A timeout of -1 returns immediately; a timeout + * of 0 waits indefinitely. + * @return The number of events read. + */ + private static native int kevent(int kq, ByteBuffer events, int nevents, + long timeout); + + /** + * Fetch a polled key from a native state buffer. For each kevent key we + * create, we put the native state info (one or more struct + * kevents) in that key's {@link KqueueSelectionKeyImpl#nstate} + * buffer, and place the pointer of the key in the udata field + * of that structure. This method fetches that pointer from the given + * buffer (assumed to be a struct kqueue) and returns it. + * + * @param nstate The buffer containing the struct kqueue to read. + * @return The key object. + */ + private static native int fetch_key(ByteBuffer nstate); + + /** + * Fetch the ready ops of the associated native state. That is, this + * inspects the first argument as a struct kevent, looking + * at its operation (the input is assumed to have been returned via a + * previous call to kevent), and translating that to the + * appropriate Java bit set, based on the second argument. + * + * @param nstate The native state. + * @param interestOps The enabled operations for the key. + * @return The bit set representing the ready operations. + */ + private static native int ready_ops(ByteBuffer nstate, int interestOps); + + /** + * Check if kevent returned EV_EOF for a selection key. + * + * @param nstate The native state. + * @return True if the kevent call returned EOF. + */ + private static native boolean check_eof(ByteBuffer nstate); +} 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 17 Sep 2006 06:17:12 -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/NIOSocketImpl.java =================================================================== RCS file: gnu/java/nio/NIOSocketImpl.java diff -N gnu/java/nio/NIOSocketImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/nio/NIOSocketImpl.java 17 Sep 2006 06:17:12 -0000 @@ -0,0 +1,110 @@ +/* NIOSocketImpl.java -- subclass of PlainSocketImpl for NIO. + Copyright (C) 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; + +import gnu.java.net.PlainSocketImpl; + +import java.io.IOException; +import java.net.InetAddress; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class NIOSocketImpl extends PlainSocketImpl +{ + + private final SocketChannelImpl channel; + + NIOSocketImpl(SocketChannelImpl channel) throws IOException + { + this.channel = channel; + impl.getState().setChannelFD(channel.getVMChannel().getState()); + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getInetAddress() + */ + //@Override + protected InetAddress getInetAddress() + { + try + { + return channel.getVMChannel().getPeerAddress().getAddress(); + } + catch (IOException ioe) + { + return null; + } + catch (NullPointerException npe) + { + // Socket is not connected yet. + return null; + } + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getPort() + */ + //@Override + protected int getPort() + { + try + { + return channel.getVMChannel().getPeerAddress().getPort(); + } + catch (IOException ioe) + { + return -1; + } + catch (NullPointerException npe) + { + // Socket is not connected yet. + return -1; + } + } + + /* (non-Javadoc) + * @see gnu.java.net.PlainSocketImpl#create(boolean) + */ + //@Override + protected synchronized void create(boolean stream) + { + // Ignored; the socket has already been created. + } +} 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 17 Sep 2006 06:17:12 -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 17 Sep 2006 06:17:12 -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 17 Sep 2006 06:17:12 -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 17 Sep 2006 06:17:12 -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 17 Sep 2006 06:17:12 -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 17 Sep 2006 06:17:12 -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 17 Sep 2006 06:17:12 -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 17 Sep 2006 06:17:12 -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/VMChannelOwner.java =================================================================== RCS file: gnu/java/nio/VMChannelOwner.java diff -N gnu/java/nio/VMChannelOwner.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/nio/VMChannelOwner.java 17 Sep 2006 06:17:12 -0000 @@ -0,0 +1,60 @@ +/* NativeFD.java -- interface for Channels that have an underlying file descriptor. + Copyright (C) 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; + +import java.nio.channels.Channel; +import java.nio.channels.Selector; + +/** + * This interface is meant to be implemented by any {@link Channel} + * implementation we support that uses a platform-specific {@link VMChannel} + * at their core. This is primarily used by {@link Selector} implementations, + * for easier access to the native state. + * + * @author Casey Marshall (csm@gnu.org) + */ +interface VMChannelOwner +{ + /** + * Return the underlying platform-specific Channel instance. + * + * @return The platform channel object. + */ + VMChannel getVMChannel(); +} 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 17 Sep 2006 06:17: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: include/gnu_java_net_VMPlainSocketImpl.h =================================================================== RCS file: /cvsroot/classpath/classpath/include/gnu_java_net_VMPlainSocketImpl.h,v retrieving revision 1.2 diff -u -r1.2 gnu_java_net_VMPlainSocketImpl.h --- include/gnu_java_net_VMPlainSocketImpl.h 19 Mar 2006 23:17:16 -0000 1.2 +++ include/gnu_java_net_VMPlainSocketImpl.h 17 Sep 2006 06:17:12 -0000 @@ -1,31 +1,152 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ - -#ifndef __gnu_java_net_VMPlainSocketImpl__ -#define __gnu_java_net_VMPlainSocketImpl__ - #include +/* Header for class gnu_java_net_VMPlainSocketImpl */ +#ifndef _Included_gnu_java_net_VMPlainSocketImpl +#define _Included_gnu_java_net_VMPlainSocketImpl #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_setOption (JNIEnv *env, jclass, jobject, jint, jobject); -JNIEXPORT jobject JNICALL Java_gnu_java_net_VMPlainSocketImpl_getOption (JNIEnv *env, jclass, jobject, jint); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_create (JNIEnv *env, jclass, jobject); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_connect (JNIEnv *env, jclass, jobject, jobject, jint); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_bind (JNIEnv *env, jclass, jobject, jobject, jint); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_listen (JNIEnv *env, jclass, jobject, jint); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_accept (JNIEnv *env, jclass, jobject, jobject); -JNIEXPORT jint JNICALL Java_gnu_java_net_VMPlainSocketImpl_available (JNIEnv *env, jclass, jobject); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_close (JNIEnv *env, jclass, jobject); -JNIEXPORT jint JNICALL Java_gnu_java_net_VMPlainSocketImpl_read (JNIEnv *env, jclass, jobject, jbyteArray, jint, jint); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_write (JNIEnv *env, jclass, jobject, jbyteArray, jint, jint); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_shutdownInput (JNIEnv *env, jclass, jobject); -JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput (JNIEnv *env, jclass, jobject); +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: setOption + * Signature: (III)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_setOption + (JNIEnv *, jclass, jint, jint, jint); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: getOption + * Signature: (II)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_net_VMPlainSocketImpl_getOption + (JNIEnv *, jclass, jint, jint); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: bind + * Signature: (I[BI)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_bind + (JNIEnv *, jclass, jint, jbyteArray, jint); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: bind6 + * Signature: (I[BI)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_bind6 + (JNIEnv *, jclass, jint, jbyteArray, jint); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: listen + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_listen + (JNIEnv *, jclass, jint, jint); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: join + * Signature: (I[B)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_join + (JNIEnv *, jclass, jint, jbyteArray); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: join6 + * Signature: (I[B)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_join6 + (JNIEnv *, jclass, jint, jbyteArray); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leave + * Signature: (I[B)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_leave + (JNIEnv *, jclass, jint, jbyteArray); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leave6 + * Signature: (I[B)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_leave6 + (JNIEnv *, jclass, jint, jbyteArray); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: joinGroup + * Signature: (I[BLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_joinGroup + (JNIEnv *, jclass, jint, jbyteArray, jstring); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: joinGroup6 + * Signature: (I[BLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_joinGroup6 + (JNIEnv *, jclass, jint, jbyteArray, jstring); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leaveGroup + * Signature: (I[BLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_leaveGroup + (JNIEnv *, jclass, jint, jbyteArray, jstring); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leaveGroup6 + * Signature: (I[BLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_leaveGroup6 + (JNIEnv *, jclass, jint, jbyteArray, jstring); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: shutdownInput + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_shutdownInput + (JNIEnv *, jclass, jint); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: shutdownOutput + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput + (JNIEnv *, jclass, jint); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: sendUrgentData + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_gnu_java_net_VMPlainSocketImpl_sendUrgentData + (JNIEnv *, jclass, jint, jint); #ifdef __cplusplus } #endif +#endif +/* Header for class gnu_java_net_VMPlainSocketImpl_State */ -#endif /* __gnu_java_net_VMPlainSocketImpl__ */ +#ifndef _Included_gnu_java_net_VMPlainSocketImpl_State +#define _Included_gnu_java_net_VMPlainSocketImpl_State +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif Index: include/gnu_java_nio_FileChannelImpl.h =================================================================== RCS file: include/gnu_java_nio_FileChannelImpl.h diff -N include/gnu_java_nio_FileChannelImpl.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/gnu_java_nio_FileChannelImpl.h 17 Sep 2006 06:17:12 -0000 @@ -0,0 +1,25 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class gnu_java_nio_FileChannelImpl */ + +#ifndef _Included_gnu_java_nio_FileChannelImpl +#define _Included_gnu_java_nio_FileChannelImpl +#ifdef __cplusplus +extern "C" { +#endif +#undef gnu_java_nio_FileChannelImpl_READ +#define gnu_java_nio_FileChannelImpl_READ 1L +#undef gnu_java_nio_FileChannelImpl_WRITE +#define gnu_java_nio_FileChannelImpl_WRITE 2L +#undef gnu_java_nio_FileChannelImpl_APPEND +#define gnu_java_nio_FileChannelImpl_APPEND 4L +#undef gnu_java_nio_FileChannelImpl_EXCL +#define gnu_java_nio_FileChannelImpl_EXCL 8L +#undef gnu_java_nio_FileChannelImpl_SYNC +#define gnu_java_nio_FileChannelImpl_SYNC 16L +#undef gnu_java_nio_FileChannelImpl_DSYNC +#define gnu_java_nio_FileChannelImpl_DSYNC 32L +#ifdef __cplusplus +} +#endif +#endif Index: include/gnu_java_nio_KqueueSelectorImpl.h =================================================================== RCS file: include/gnu_java_nio_KqueueSelectorImpl.h diff -N include/gnu_java_nio_KqueueSelectorImpl.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/gnu_java_nio_KqueueSelectorImpl.h 17 Sep 2006 06:17:12 -0000 @@ -0,0 +1,85 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class gnu_java_nio_KqueueSelectorImpl */ + +#ifndef _Included_gnu_java_nio_KqueueSelectorImpl +#define _Included_gnu_java_nio_KqueueSelectorImpl +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: kqueue_supported + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_gnu_java_nio_KqueueSelectorImpl_kqueue_1supported + (JNIEnv *, jclass); + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: sizeof_struct_kevent + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_KqueueSelectorImpl_sizeof_1struct_1kevent + (JNIEnv *, jclass); + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: implOpen + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_KqueueSelectorImpl_implOpen + (JNIEnv *, jclass); + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: implClose + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_gnu_java_nio_KqueueSelectorImpl_implClose + (JNIEnv *, jclass, jint); + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: kevent_set + * Signature: (Ljava/nio/ByteBuffer;IIIZ)V + */ +JNIEXPORT void JNICALL Java_gnu_java_nio_KqueueSelectorImpl_kevent_1set + (JNIEnv *, jclass, jobject, jint, jint, jint, jboolean); + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: kevent + * Signature: (ILjava/nio/ByteBuffer;IJ)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_KqueueSelectorImpl_kevent + (JNIEnv *, jclass, jint, jobject, jint, jlong); + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: fetch_key + * Signature: (Ljava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_KqueueSelectorImpl_fetch_1key + (JNIEnv *, jclass, jobject); + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: ready_ops + * Signature: (Ljava/nio/ByteBuffer;I)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_KqueueSelectorImpl_ready_1ops + (JNIEnv *, jclass, jobject, jint); + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: check_eof + * Signature: (Ljava/nio/ByteBuffer;)Z + */ +JNIEXPORT jboolean JNICALL Java_gnu_java_nio_KqueueSelectorImpl_check_1eof + (JNIEnv *, jclass, jobject); + +#ifdef __cplusplus +} +#endif +#endif Index: include/gnu_java_nio_VMChannel.h =================================================================== RCS file: /cvsroot/classpath/classpath/include/gnu_java_nio_VMChannel.h,v retrieving revision 1.1 diff -u -r1.1 gnu_java_nio_VMChannel.h --- include/gnu_java_nio_VMChannel.h 14 May 2006 03:34:55 -0000 1.1 +++ include/gnu_java_nio_VMChannel.h 17 Sep 2006 06:17:12 -0000 @@ -1,24 +1,291 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ - -#ifndef __gnu_java_nio_VMChannel__ -#define __gnu_java_nio_VMChannel__ - #include +/* Header for class gnu_java_nio_VMChannel */ +#ifndef _Included_gnu_java_nio_VMChannel +#define _Included_gnu_java_nio_VMChannel #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif +/* + * Class: gnu_java_nio_VMChannel + * Method: stdin_fd + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_stdin_1fd + (JNIEnv *, jclass); + +/* + * Class: gnu_java_nio_VMChannel + * Method: stdout_fd + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_stdout_1fd + (JNIEnv *, jclass); + +/* + * Class: gnu_java_nio_VMChannel + * Method: stderr_fd + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_stderr_1fd + (JNIEnv *, jclass); + +/* + * Class: gnu_java_nio_VMChannel + * Method: setBlocking + * Signature: (IZ)V + */ +JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_setBlocking + (JNIEnv *, jclass, jint, jboolean); + +/* + * Class: gnu_java_nio_VMChannel + * Method: available + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_available + (JNIEnv *, jclass, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: read + * Signature: (ILjava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2 + (JNIEnv *, jclass, jint, jobject); + +/* + * Class: gnu_java_nio_VMChannel + * Method: read + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_read__I + (JNIEnv *, jclass, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: readScattering + * Signature: (I[Ljava/nio/ByteBuffer;II)J + */ +JNIEXPORT jlong JNICALL Java_gnu_java_nio_VMChannel_readScattering + (JNIEnv *, jclass, jint, jobjectArray, jint, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: receive + * Signature: (ILjava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_receive + (JNIEnv *, jclass, jint, jobject, jobject); + +/* + * Class: gnu_java_nio_VMChannel + * Method: write + * Signature: (ILjava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2 + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: gnu_java_nio_VMChannel + * Method: writeGathering + * Signature: (I[Ljava/nio/ByteBuffer;II)J + */ +JNIEXPORT jlong JNICALL Java_gnu_java_nio_VMChannel_writeGathering + (JNIEnv *, jobject, jint, jobjectArray, jint, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: send + * Signature: (ILjava/nio/ByteBuffer;[BI)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_send + (JNIEnv *, jclass, jint, jobject, jbyteArray, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: send6 + * Signature: (ILjava/nio/ByteBuffer;[BI)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_send6 + (JNIEnv *, jclass, jint, jobject, jbyteArray, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: write + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_write__II + (JNIEnv *, jclass, jint, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: initIDs + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_initIDs + (JNIEnv *, jclass); + +/* + * Class: gnu_java_nio_VMChannel + * Method: socket + * Signature: (Z)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_socket + (JNIEnv *, jclass, jboolean); + +/* + * Class: gnu_java_nio_VMChannel + * Method: connect + * Signature: (I[BII)Z + */ +JNIEXPORT jboolean JNICALL Java_gnu_java_nio_VMChannel_connect + (JNIEnv *, jclass, jint, jbyteArray, jint, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: connect6 + * Signature: (I[BII)Z + */ +JNIEXPORT jboolean JNICALL Java_gnu_java_nio_VMChannel_connect6 + (JNIEnv *, jclass, jint, jbyteArray, jint, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: disconnect + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_disconnect + (JNIEnv *, jclass, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: getsockname + * Signature: (ILjava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_getsockname + (JNIEnv *, jclass, jint, jobject); + +/* + * Class: gnu_java_nio_VMChannel + * Method: getpeername + * Signature: (ILjava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_getpeername + (JNIEnv *, jclass, jint, jobject); + +/* + * Class: gnu_java_nio_VMChannel + * Method: accept + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_accept + (JNIEnv *, jclass, jint); -JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env, jobject, jint, jboolean); -JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_read (JNIEnv *env, jobject, jint, jobject); -JNIEXPORT jlong JNICALL Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env, jobject, jint, jobjectArray, jint, jint); -JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_write (JNIEnv *env, jobject, jint, jobject); -JNIEXPORT jlong JNICALL Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env, jobject, jint, jobjectArray, jint, jint); -JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_initIDs (JNIEnv *env, jclass); +/* + * Class: gnu_java_nio_VMChannel + * Method: open + * Signature: (Ljava/lang/String;I)I + */ +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_open + (JNIEnv *, jclass, jstring, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: position + * Signature: (I)J + */ +JNIEXPORT jlong JNICALL Java_gnu_java_nio_VMChannel_position + (JNIEnv *, jclass, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: seek + * Signature: (IJ)V + */ +JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_seek + (JNIEnv *, jclass, jint, jlong); + +/* + * Class: gnu_java_nio_VMChannel + * Method: truncate + * Signature: (IJ)V + */ +JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_truncate + (JNIEnv *, jclass, jint, jlong); + +/* + * Class: gnu_java_nio_VMChannel + * Method: lock + * Signature: (IJJZZ)Z + */ +JNIEXPORT jboolean JNICALL Java_gnu_java_nio_VMChannel_lock + (JNIEnv *, jclass, jint, jlong, jlong, jboolean, jboolean); + +/* + * Class: gnu_java_nio_VMChannel + * Method: unlock + * Signature: (IJJ)V + */ +JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_unlock + (JNIEnv *, jclass, jint, jlong, jlong); + +/* + * Class: gnu_java_nio_VMChannel + * Method: size + * Signature: (I)J + */ +JNIEXPORT jlong JNICALL Java_gnu_java_nio_VMChannel_size + (JNIEnv *, jclass, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: map + * Signature: (ICJI)Ljava/nio/MappedByteBuffer; + */ +JNIEXPORT jobject JNICALL Java_gnu_java_nio_VMChannel_map + (JNIEnv *, jclass, jint, jchar, jlong, jint); + +/* + * Class: gnu_java_nio_VMChannel + * Method: flush + * Signature: (IZ)Z + */ +JNIEXPORT jboolean JNICALL Java_gnu_java_nio_VMChannel_flush + (JNIEnv *, jclass, jint, jboolean); + +/* + * Class: gnu_java_nio_VMChannel + * Method: close + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_close + (JNIEnv *, jclass, jint); #ifdef __cplusplus } #endif +#endif +/* Header for class gnu_java_nio_VMChannel_State */ -#endif /* __gnu_java_nio_VMChannel__ */ +#ifndef _Included_gnu_java_nio_VMChannel_State +#define _Included_gnu_java_nio_VMChannel_State +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class gnu_java_nio_VMChannel_Kind */ + +#ifndef _Included_gnu_java_nio_VMChannel_Kind +#define _Included_gnu_java_nio_VMChannel_Kind +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif Index: include/gnu_java_nio_VMPipe.h =================================================================== RCS file: /cvsroot/classpath/classpath/include/gnu_java_nio_VMPipe.h,v retrieving revision 1.2 diff -u -r1.2 gnu_java_nio_VMPipe.h --- include/gnu_java_nio_VMPipe.h 30 Jul 2004 23:16:58 -0000 1.2 +++ include/gnu_java_nio_VMPipe.h 17 Sep 2006 06:17:12 -0000 @@ -1,19 +1,21 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ - -#ifndef __gnu_java_nio_VMPipe__ -#define __gnu_java_nio_VMPipe__ - #include +/* Header for class gnu_java_nio_VMPipe */ +#ifndef _Included_gnu_java_nio_VMPipe +#define _Included_gnu_java_nio_VMPipe #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - -JNIEXPORT void JNICALL Java_gnu_java_nio_VMPipe_init (JNIEnv *env, jclass, jobject, jobject); +/* + * Class: gnu_java_nio_VMPipe + * Method: pipe0 + * Signature: ()[I + */ +JNIEXPORT jintArray JNICALL Java_gnu_java_nio_VMPipe_pipe0 + (JNIEnv *, jclass); #ifdef __cplusplus } #endif - -#endif /* __gnu_java_nio_VMPipe__ */ +#endif Index: include/java_net_VMNetworkInterface.h =================================================================== RCS file: /cvsroot/classpath/classpath/include/java_net_VMNetworkInterface.h,v retrieving revision 1.1 diff -u -r1.1 java_net_VMNetworkInterface.h --- include/java_net_VMNetworkInterface.h 11 Apr 2005 18:58:38 -0000 1.1 +++ include/java_net_VMNetworkInterface.h 17 Sep 2006 06:17:12 -0000 @@ -1,19 +1,29 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ - -#ifndef __java_net_VMNetworkInterface__ -#define __java_net_VMNetworkInterface__ - #include +/* Header for class java_net_VMNetworkInterface */ +#ifndef _Included_java_net_VMNetworkInterface +#define _Included_java_net_VMNetworkInterface #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - -JNIEXPORT jobject JNICALL Java_java_net_VMNetworkInterface_getInterfaces (JNIEnv *env, jclass); +/* + * Class: java_net_VMNetworkInterface + * Method: initIds + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_java_net_VMNetworkInterface_initIds + (JNIEnv *, jclass); + +/* + * Class: java_net_VMNetworkInterface + * Method: getVMInterfaces + * Signature: ()[Ljava/net/VMNetworkInterface; + */ +JNIEXPORT jobjectArray JNICALL Java_java_net_VMNetworkInterface_getVMInterfaces + (JNIEnv *, jclass); #ifdef __cplusplus } #endif - -#endif /* __java_net_VMNetworkInterface__ */ +#endif 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 17 Sep 2006 06:17: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 17 Sep 2006 06:17:13 -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 17 Sep 2006 06:17:13 -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 17 Sep 2006 06:17: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 17 Sep 2006 06:17:13 -0000 @@ -1,5 +1,5 @@ /* DatagramSocket.java -- A class to model UDP sockets - Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005 + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -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 17 Sep 2006 06:17: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 17 Sep 2006 06:17: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 17 Sep 2006 06:17:13 -0000 @@ -1,5 +1,5 @@ /* Socket.java -- Client socket implementation - Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004 + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -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: native/jni/classpath/jcl.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/classpath/jcl.c,v retrieving revision 1.23 diff -u -r1.23 jcl.c --- native/jni/classpath/jcl.c 3 Apr 2006 14:03:12 -0000 1.23 +++ native/jni/classpath/jcl.c 17 Sep 2006 06:17:14 -0000 @@ -48,6 +48,65 @@ #endif #endif +/* + * Cached Pointer class info. + */ +static jclass rawDataClass; +static jfieldID rawData_fid; +static jmethodID rawData_mid; + +/* + * JNI OnLoad constructor. + */ +jint +JNI_OnLoad (JavaVM *vm, void *reserved) +{ + JNIEnv *env; + void *envp; + + if ((*vm)->GetEnv (vm, &envp, JNI_VERSION_1_4) != JNI_OK) + { + return JNI_VERSION_1_4; + } + env = (JNIEnv *) envp; +#if SIZEOF_VOID_P == 8 + rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer64"); + if (rawDataClass != NULL) + { + jclass tmp = rawDataClass; + rawDataClass = (*env)->NewGlobalRef (env, rawDataClass); + (*env)->DeleteGlobalRef (env, tmp); + } + + if (rawDataClass != NULL) + { + rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "J"); + rawData_mid = (*env)->GetMethodID (env, rawDataClass, "", "(J)V"); + } +#else +#if SIZEOF_VOID_P == 4 + rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer32"); + if (rawDataClass != NULL) + { + jclass tmp = rawDataClass; + rawDataClass = (*env)->NewGlobalRef (env, rawDataClass); + (*env)->DeleteGlobalRef (env, tmp); + } + + if (rawDataClass != NULL) + { + rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "I"); + rawData_mid = (*env)->GetMethodID (env, rawDataClass, "", "(I)V"); + } +#else +#error "Pointer size is not supported." +#endif /* SIZEOF_VOID_P == 4 */ +#endif /* SIZEOF_VOID_P == 8 */ + + return JNI_VERSION_1_4; +} + + JNIEXPORT void JNICALL JCL_ThrowException (JNIEnv * env, const char *className, const char *errMsg) { @@ -183,78 +242,17 @@ /* - * Build a Pointer object. The function caches the class type + * Build a Pointer object. */ -static jclass rawDataClass; -static jfieldID rawData_fid; -static jmethodID rawData_mid; - JNIEXPORT jobject JNICALL JCL_NewRawDataObject (JNIEnv * env, void *data) { - if (rawDataClass == NULL) + if (rawDataClass == NULL || rawData_mid == NULL) { - jclass tmp; -#if SIZEOF_VOID_P == 8 - rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer64"); - if (rawDataClass == NULL) - { - JCL_ThrowException (env, "java/lang/InternalError", - "unable to find internal class"); - return NULL; - } - - rawData_mid = (*env)->GetMethodID (env, rawDataClass, "", "(J)V"); - if (rawData_mid == NULL) - { - JCL_ThrowException (env, "java/lang/InternalError", - "unable to find internal constructor"); - return NULL; - } - - rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "J"); - if (rawData_fid == NULL) - { - JCL_ThrowException (env, "java/lang/InternalError", - "unable to find internal field"); - return NULL; - } -#else - rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer32"); - if (rawDataClass == NULL) - { - JCL_ThrowException (env, "java/lang/InternalError", - "unable to find internal class"); - return NULL; - } - - rawData_mid = (*env)->GetMethodID (env, rawDataClass, "", "(I)V"); - if (rawData_mid == NULL) - { - JCL_ThrowException (env, "java/lang/InternalError", - "unable to find internal constructor"); - return NULL; - } - - rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "I"); - if (rawData_fid == NULL) - { - JCL_ThrowException (env, "java/lang/InternalError", - "unable to find internal field"); - return NULL; - } - -#endif - tmp = (*env)->NewGlobalRef (env, rawDataClass); - if (tmp == NULL) - { - JCL_ThrowException (env, "java/lang/InternalError", - "unable to create an internal global ref"); - return NULL; - } - (*env)->DeleteLocalRef(env, rawDataClass); - rawDataClass = tmp; + JCL_ThrowException (env, "java/lang/InternalError", + "Pointer class was not properly initialized"); + return NULL; } #if SIZEOF_VOID_P == 8 @@ -267,6 +265,13 @@ JNIEXPORT void * JNICALL JCL_GetRawData (JNIEnv * env, jobject rawdata) { + if (rawData_fid == NULL) + { + JCL_ThrowException (env, "java/lang/InternalError", + "Pointer class was not properly initialized"); + return NULL; + } + #if SIZEOF_VOID_P == 8 return (void *) (*env)->GetLongField (env, rawdata, rawData_fid); #else Index: native/jni/java-lang/java_lang_VMProcess.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/java-lang/java_lang_VMProcess.c,v retrieving revision 1.11 diff -u -r1.11 java_lang_VMProcess.c --- native/jni/java-lang/java_lang_VMProcess.c 5 Sep 2006 21:33:25 -0000 1.11 +++ native/jni/java-lang/java_lang_VMProcess.c 17 Sep 2006 06:17:15 -0000 @@ -38,7 +38,7 @@ #include #include "java_lang_VMProcess.h" -#include "gnu_java_nio_channels_FileChannelImpl.h" +#include "gnu_java_nio_FileChannelImpl.h" #include #include @@ -137,8 +137,8 @@ char *dir = NULL; pid_t pid = -1; char errbuf[64]; - jmethodID method; - jclass clazz; + jmethodID method, vmmethod; + jclass clazz, vmclazz; int i; int pipe_count = redirect ? 2 : 3; int err; @@ -214,10 +214,12 @@ } /* Create Input/OutputStream objects around parent file descriptors */ - clazz = (*env)->FindClass (env, "gnu/java/nio/channels/FileChannelImpl"); + vmclazz = (*env)->FindClass (env, "gnu/java/nio/VMChannel"); + clazz = (*env)->FindClass (env, "gnu/java/nio/FileChannelImpl"); if ((*env)->ExceptionOccurred (env)) goto done; - method = (*env)->GetMethodID (env, clazz, "", "(II)V"); + vmmethod = (*env)->GetMethodID (env, vmclazz, "", "(I)V"); + method = (*env)->GetMethodID (env, clazz, "", "(Lgnu/java/nio/VMChannel;I)V"); if ((*env)->ExceptionOccurred (env)) goto done; for (i = 0; i < pipe_count; i++) @@ -228,11 +230,16 @@ jclass sclazz; jmethodID smethod; - jobject channel = (*env)->NewObject (env, clazz, method, fd, mode); + jobject vmchannel; + jobject channel; + vmchannel = (*env)->NewObject (env, vmclazz, vmmethod, fd); + if ((*env)->ExceptionOccurred (env)) + goto done; + channel = (*env)->NewObject (env, clazz, method, vmchannel, mode); if ((*env)->ExceptionOccurred (env)) goto done; - if (mode == gnu_java_nio_channels_FileChannelImpl_WRITE) + if (mode == gnu_java_nio_FileChannelImpl_WRITE) sclazz = (*env)->FindClass (env, "java/io/FileOutputStream"); else sclazz = (*env)->FindClass (env, "java/io/FileInputStream"); @@ -240,7 +247,7 @@ goto done; smethod = (*env)->GetMethodID (env, sclazz, "", - "(Lgnu/java/nio/channels/FileChannelImpl;)V"); + "(Lgnu/java/nio/FileChannelImpl;)V"); if ((*env)->ExceptionOccurred (env)) goto done; Index: native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c,v retrieving revision 1.6 diff -u -r1.6 gnu_java_net_VMPlainSocketImpl.c --- native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c 21 Aug 2006 23:34:45 -0000 1.6 +++ native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c 17 Sep 2006 06:17:15 -0000 @@ -35,265 +35,801 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ -/* do not move; needed here because of some macro definitions */ + +#ifdef HAVE_CONFIG_H #include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include #include #include -#include -#include -#include "javanet.h" +/* #include "javanet.h" */ #include "gnu_java_net_VMPlainSocketImpl.h" -/* - * Note that the functions in this module simply redirect to another - * internal function. Why? Because many of these functions are shared - * with PlainDatagramSocketImpl. The unshared ones were done the same - * way for consistency. - */ +#define IO_EXCEPTION "java/io/IOException" +#define SOCKET_EXCEPTION "java/net/SocketException" +#define BIND_EXCEPTION "java/net/BindException" + +#define THROW_NO_NETWORK(env) JCL_ThrowException (env, "java/lang/InternalError", "this platform not configured for network support") -/*************************************************************************/ /* - * Creates a new stream or datagram socket + * Class: gnu_java_net_VMPlainSocketImpl + * Method: bind + * Signature: (I[BI)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_create(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj) +Java_gnu_java_net_VMPlainSocketImpl_bind (JNIEnv *env, + jclass clazz __attribute__((unused)), + jint fd, jbyteArray addr, jint port) { -#ifndef WITHOUT_NETWORK - _javanet_create(env, obj, JNI_TRUE); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ + struct sockaddr_in sockaddr; + jbyte *elems = NULL; + int ret; + + if (addr != NULL) + elems = (*env)->GetByteArrayElements (env, addr, NULL); + + memset(&sockaddr, 0, sizeof (struct sockaddr_in)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons (port); + /* addr is already in network byte order. */ + if (elems != NULL) + sockaddr.sin_addr.s_addr = *((uint32_t *) elems); + else + sockaddr.sin_addr.s_addr = INADDR_ANY; + + /* bind(2) from BSD says bind will never return EINTR */ + /* bind is not a blocking system call */ + ret = bind (fd, (struct sockaddr *) &sockaddr, sizeof (struct sockaddr_in)); + + if (elems != NULL) + (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT); + + if (-1 == ret) + JCL_ThrowException (env, BIND_EXCEPTION, strerror (errno)); } -/*************************************************************************/ /* - * Close the socket. Any underlying streams will be closed by this - * action as well. + * Class: gnu_java_net_VMPlainSocketImpl + * Method: bind6 + * Signature: (I[BI)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_close(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj) +Java_gnu_java_net_VMPlainSocketImpl_bind6 (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr, jint port) { -#ifndef WITHOUT_NETWORK - _javanet_close(env, obj, 1); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ + /* FIXME! Add check if we have IPv6! */ + struct sockaddr_in6 sockaddr; + jbyte *elems; + int ret; + + elems = (*env)->GetByteArrayElements (env, addr, NULL); + + memset (&sockaddr, 0, sizeof (struct sockaddr_in6)); + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = htons (port); + memcpy (&sockaddr.sin6_addr.s6_addr, elems, 16); + + /* bind(2) from BSD says bind will never return EINTR */ + /* bind is not a blocking system call */ + ret = bind (fd, (struct sockaddr *) &sockaddr, + sizeof (struct sockaddr_in6)); + + (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT); + + if (-1 == ret) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); } -/*************************************************************************/ /* - * Connects to the specified destination. + * Class: gnu_java_net_VMPlainSocketImpl + * Method: listen + * Signature: (II)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_connect(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jobject addr, jint port) -{ -#ifndef WITHOUT_NETWORK - _javanet_connect(env, obj, addr, port, 1); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ +Java_gnu_java_net_VMPlainSocketImpl_listen (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jint backlog) +{ + int ret; + + /* listen(2) says that this call will never return EINTR */ + /* listen is not a blocking system call */ + if ((ret = listen (fd, backlog)) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + printf("listen returns %d\n", ret); } -/*************************************************************************/ + +/* These constants are also defined in java/net/SocketOptions.java */ +enum java_sockopt { + CPNET_SO_KEEPALIVE = 0x8, + CPNET_SO_LINGER = 0x80, + CPNET_SO_TIMEOUT = 0x1006, + CPNET_SO_BINDADDR = 0x0F, + CPNET_SO_SNDBUF = 0x1001, + CPNET_SO_RCVBUF = 0x1002, + CPNET_SO_REUSEADDR = 0x04, + CPNET_SO_BROADCAST = 0x20, + CPNET_SO_OOBINLINE = 0x1003, + CPNET_TCP_NODELAY = 0x01, + CPNET_IP_MULTICAST_IF = 0x10, + CPNET_IP_MULTICAST_IF2 = 0x1F, + CPNET_IP_MULTICAST_LOOP = 0x12, + CPNET_IP_TOS = 0x03 +}; + /* - * This method binds the specified address to the specified local port. - * Note that we have to set the local address and local port public instance - * variables. + * Class: gnu_java_net_VMPlainSocketImpl + * Method: setOption + * Signature: (III)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_bind(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, jobject addr, - jint port) -{ -#ifndef WITHOUT_NETWORK - _javanet_bind(env, obj, addr, port, 1); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ +Java_gnu_java_net_VMPlainSocketImpl_setOption (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jint option, jint value) +{ + enum java_sockopt joption = (enum java_sockopt) option; + int optname = -1; + int level = SOL_SOCKET; + const int _value = value; + struct linger _linger; + struct timeval _timeo; + void *optval = (void *) &_value; + socklen_t optlen = sizeof (int); + + switch (joption) + { + case CPNET_IP_MULTICAST_LOOP: + level = IPPROTO_IP; + optname = IP_MULTICAST_LOOP; + break; + + case CPNET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + break; + + case CPNET_SO_LINGER: + optname = SO_LINGER; + if (_value == 0) + _linger.l_onoff = 0; + else + _linger.l_onoff = 1; + _linger.l_linger = _value; + optval = &_linger; + optlen = sizeof (struct linger); + break; + + case CPNET_SO_TIMEOUT: + optname = SO_RCVTIMEO; + _timeo.tv_sec = value / 1000; + _timeo.tv_usec = (value % 1000) * 1000; + optval = &_timeo; + optlen = sizeof (struct timeval); + break; + + case CPNET_SO_SNDBUF: + optname = SO_SNDBUF; + break; + + case CPNET_SO_RCVBUF: + optname = SO_RCVBUF; + break; + + case CPNET_SO_REUSEADDR: + optname = SO_REUSEADDR; + break; + + case CPNET_SO_BROADCAST: + optname = SO_BROADCAST; + break; + + case CPNET_SO_OOBINLINE: + optname = SO_OOBINLINE; + break; + + case CPNET_TCP_NODELAY: + level = IPPROTO_TCP; + optname = TCP_NODELAY; + break; + + case CPNET_IP_TOS: + level = IPPROTO_IP; + optname = IP_TOS; + break; + + case CPNET_SO_BINDADDR: + case CPNET_IP_MULTICAST_IF: + case CPNET_IP_MULTICAST_IF2: + JCL_ThrowException (env, IO_EXCEPTION, "argument not a boolean or integer option"); + return; + } + + if (setsockopt (fd, level, optname, (const void *) optval, optlen) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); +} + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: getOption + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_net_VMPlainSocketImpl_getOption (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jint option) +{ + enum java_sockopt joption = (enum java_sockopt) option; + int optname = -1; + int level = SOL_SOCKET; + int value; + struct linger linger; + struct timeval timeo; + void *optval = &value; + socklen_t optlen = sizeof (int); + + switch (joption) + { + case CPNET_IP_MULTICAST_LOOP: + level = IPPROTO_IP; + optname = IP_MULTICAST_LOOP; + break; + + case CPNET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + break; + + case CPNET_SO_LINGER: + optname = SO_LINGER; + optval = &linger; + optlen = sizeof (struct linger); + break; + + case CPNET_SO_TIMEOUT: + optname = SO_RCVTIMEO; + optval = &timeo; + optlen = sizeof (struct timeval); + break; + + case CPNET_SO_SNDBUF: + optname = SO_SNDBUF; + break; + + case CPNET_SO_RCVBUF: + optname = SO_RCVBUF; + break; + + case CPNET_SO_REUSEADDR: + optname = SO_REUSEADDR; + break; + + case CPNET_SO_BROADCAST: + optname = SO_BROADCAST; + break; + + case CPNET_SO_OOBINLINE: + optname = SO_OOBINLINE; + break; + + case CPNET_TCP_NODELAY: + level = IPPROTO_TCP; + optname = TCP_NODELAY; + break; + + case CPNET_IP_TOS: + level = IPPROTO_IP; + optname = IP_TOS; + break; + + case CPNET_SO_BINDADDR: + case CPNET_IP_MULTICAST_IF: + case CPNET_IP_MULTICAST_IF2: + JCL_ThrowException (env, IO_EXCEPTION, "argument not a boolean or integer option"); + return -1; + } + + if (getsockopt (fd, level, optname, optval, &optlen) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + + if (joption == CPNET_SO_LINGER) + return linger.l_linger; + if (joption == CPNET_SO_TIMEOUT) + return (timeo.tv_sec * 1000) + (timeo.tv_usec / 1000); + + return value; } -/*************************************************************************/ /* - * Starts listening on a socket with the specified number of pending - * connections allowed. + * Class: gnu_java_net_VMPlainSocketImpl + * Method: shutdownInput + * Signature: (I)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_listen(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, jint queuelen) +Java_gnu_java_net_VMPlainSocketImpl_shutdownInput (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd) { -#ifndef WITHOUT_NETWORK - _javanet_listen(env, obj, queuelen); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ + if (shutdown (fd, SHUT_RD) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); } -/*************************************************************************/ - /* - * Accepts a new connection and assigns it to the passed in SocketImpl - * object. Note that we assume this is a PlainSocketImpl just like us. + * Class: gnu_java_net_VMPlainSocketImpl + * Method: shutdownOutput + * Signature: (I)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_accept(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, jobject impl) +Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd) { -#ifndef WITHOUT_NETWORK - _javanet_accept(env, obj, impl); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ + if (shutdown (fd, SHUT_WR) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); } -/*************************************************************************/ -JNIEXPORT jint JNICALL -Java_gnu_java_net_VMPlainSocketImpl_available(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj) -{ -#ifndef WITHOUT_NETWORK - jclass cls; - jfieldID fid; - int fd; - int bytesAvailable; - int result; - - cls = (*env)->GetObjectClass(env, obj); - if (cls == 0) - { - JCL_ThrowException(env, IO_EXCEPTION, "internal error"); - return 0; - } - - fid = (*env)->GetFieldID(env, cls, "native_fd", "I"); - if (fid == 0) - { - JCL_ThrowException(env, IO_EXCEPTION, "internal error"); - return 0; - } - - fd = (*env)->GetIntField(env, obj, fid); - - result = cpnet_getAvailableBytes (env, fd, &bytesAvailable); - if (result != CPNATIVE_OK) - { - JCL_ThrowException(env, IO_EXCEPTION, cpnative_getErrorString (result)); - return 0; - } +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: sendUrgentData + * Signature: (II)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_VMPlainSocketImpl_sendUrgentData (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jint data) +{ + const char x = (char) data; - return bytesAvailable; -#else /* not WITHOUT_NETWORK */ - return 0; -#endif /* not WITHOUT_NETWORK */ + if (send (fd, &x, 1, MSG_OOB) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); } -/*************************************************************************/ /* - * This method sets the specified option for a socket + * Class: gnu_java_net_VMPlainSocketImpl + * Method: join + * Signature: (I[B)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_setOption(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jint option_id, jobject val) +Java_gnu_java_net_VMPlainSocketImpl_join (JNIEnv *env, + jclass clazz __attribute__((unused)), + jint fd, jbyteArray addr) { -#ifndef WITHOUT_NETWORK - _javanet_set_option(env, obj, option_id, val); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ +#ifdef HAVE_SETSOCKOPT + struct ip_mreq maddr; + jbyte *addr_elems; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems); + maddr.imr_interface.s_addr = INADDR_ANY; + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &maddr, sizeof (struct ip_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } -/*************************************************************************/ /* - * This method gets the specified option for a socket + * Class: gnu_java_net_VMPlainSocketImpl + * Method: join6 + * Signature: (I[B)V */ -JNIEXPORT jobject JNICALL -Java_gnu_java_net_VMPlainSocketImpl_getOption(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jint option_id) -{ -#ifndef WITHOUT_NETWORK - return(_javanet_get_option(env, obj, option_id)); -#else /* not WITHOUT_NETWORK */ - return NULL; -#endif /* not WITHOUT_NETWORK */ +JNIEXPORT void JNICALL +Java_gnu_java_net_VMPlainSocketImpl_join6 (JNIEnv *env, + jclass clazz __attribute__((unused)), + jint fd, jbyteArray addr) +{ +#ifdef HAVE_SETSOCKOPT +#ifdef HAVE_INET6 + struct ipv6_mreq maddr; + jbyte *addr_elems; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16); + maddr.ipv6mr_interface = 0; + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &maddr, sizeof (struct ipv6_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "IPv6 support not available"); +#endif /* HAVE_INET6 */ +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } -/*************************************************************************/ - /* - * Reads a buffer from a remote host + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leave + * Signature: (I[B)V */ -JNIEXPORT jint JNICALL -Java_gnu_java_net_VMPlainSocketImpl_read(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, jarray buf, - jint offset, jint len) -{ -#ifndef WITHOUT_NETWORK - return(_javanet_recvfrom(env, obj, buf, offset, len, 0)); -#else /* not WITHOUT_NETWORK */ - return 0; -#endif /* not WITHOUT_NETWORK */ +JNIEXPORT void JNICALL +Java_gnu_java_net_VMPlainSocketImpl_leave (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr) +{ +#ifdef HAVE_SETSOCKOPT + struct ip_mreq maddr; + jbyte *addr_elems; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems); + maddr.imr_interface.s_addr = INADDR_ANY; + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, + &maddr, sizeof (struct ip_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } -/*************************************************************************/ +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leave6 + * Signature: (I[B)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_VMPlainSocketImpl_leave6 (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr) +{ +#ifdef HAVE_SETSOCKOPT +#ifdef HAVE_INET6 + struct ipv6_mreq maddr; + jbyte *addr_elems; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16); + maddr.ipv6mr_interface = 0; + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &maddr, sizeof (struct ipv6_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "IPv6 support not available"); +#endif /* HAVE_INET6 */ +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ +} + +static uint32_t getif_address (JNIEnv *env, char *ifname); +static int getif_index (JNIEnv *env, char *ifname); + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: joinGroup + * Signature: (I[BILjava/lang/String;)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_VMPlainSocketImpl_joinGroup (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr, + jstring ifname) +{ +#ifdef HAVE_SETSOCKOPT + struct ip_mreq maddr; + jbyte *addr_elems; + + if (ifname != NULL) + { + maddr.imr_interface.s_addr = getif_address (env, ifname); + if ((*env)->ExceptionCheck (env)) + return; + } + else + maddr.imr_interface.s_addr = INADDR_ANY; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems); + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &maddr, sizeof (struct ip_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + (void) ifname; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ +} /* - * Writes a buffer to the remote host + * Class: gnu_java_net_VMPlainSocketImpl + * Method: joinGroup6 + * Signature: (I[BILjava/lang/String;)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_write(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, jarray buf, - jint offset, jint len) -{ -#ifndef WITHOUT_NETWORK - _javanet_sendto(env, obj, buf, offset, len, 0); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ +Java_gnu_java_net_VMPlainSocketImpl_joinGroup6 (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr, + jstring ifname) +{ +#ifdef HAVE_SETSOCKOPT +#ifdef HAVE_INET6 + struct ipv6_mreq maddr; + jbyte *addr_elems; + + if (ifname == NULL) + { + maddr.ipv6mr_interface = getif_index (env, ifname); + if ((*env)->ExceptionCheck (env)) + return; + } + else + maddr.ipv6mr_interface = 0; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16); + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &maddr, sizeof (struct ipv6_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "IPv6 support not available"); +#endif /* HAVE_INET6 */ +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leaveGroup + * Signature: (I[BILjava/lang/String;)V + */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_shutdownInput (JNIEnv * env, - jclass klass __attribute__ ((__unused__)), - jobject this) -{ -#ifndef WITHOUT_NETWORK - _javanet_shutdownInput (env, this); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ +Java_gnu_java_net_VMPlainSocketImpl_leaveGroup (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr, + jstring ifname) +{ +#ifdef HAVE_SETSOCKOPT + struct ip_mreq maddr; + jbyte *addr_elems; + + if (ifname != NULL) + { + maddr.imr_interface.s_addr = getif_address (env, ifname); + if ((*env)->ExceptionCheck (env)) + return; + } + else + maddr.imr_interface.s_addr = INADDR_ANY; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems); + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, + &maddr, sizeof (struct ip_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + (void) ifname; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leaveGroup6 + * Signature: (I[BILjava/lang/String;)V + */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput (JNIEnv * env, - jclass klass __attribute__ ((__unused__)), - jobject this) -{ -#ifndef WITHOUT_NETWORK - _javanet_shutdownOutput (env, this); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ +Java_gnu_java_net_VMPlainSocketImpl_leaveGroup6 (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr, + jstring ifname) +{ +#ifdef HAVE_SETSOCKOPT +#ifdef HAVE_INET6 + struct ipv6_mreq maddr; + jbyte *addr_elems; + + if (ifname == NULL) + { + maddr.ipv6mr_interface = getif_index (env, ifname); + if ((*env)->ExceptionCheck (env)) + return; + } + else + maddr.ipv6mr_interface = 0; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16); + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + &maddr, sizeof (struct ipv6_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "IPv6 support not available"); +#endif /* HAVE_INET6 */ +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ +} + +static uint32_t +getif_address (JNIEnv *env, char *ifname) +{ +#ifdef HAVE_GETIFADDRS + struct ifaddrs *ifaddrs, *i; + uint32_t addr = 0; + int foundaddr = 0; + + if (getifaddrs (&ifaddrs) == -1) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); + return 0; + } + + for (i = ifaddrs; i != NULL; i = i->ifa_next) + { + if (strcmp (ifname, i->ifa_name) == 0) + { + /* Matched the name; see if there is an IPv4 address. */ + if (i->ifa_addr->sa_family == AF_INET) + { + foundaddr = 1; + addr = ((struct sockaddr_in *) i->ifa_addr)->sin_addr.s_addr; + break; + } + } + } + + if (!foundaddr) + JCL_ThrowException (env, SOCKET_EXCEPTION, "interface has no IPv4 address"); + + freeifaddrs (ifaddrs); + + return addr; +#else + (void) ifname; + JCL_ThrowException (env, "java/lang/InternalError", + "getifaddrs not available"); + return 0; +#endif /* HAVE_GETIFADDRS */ } -/* end of file */ +static int +getif_index (JNIEnv *env, char *ifname) +{ +#ifdef HAVE_GETIFADDRS + struct ifaddrs *ifaddrs, *i; + char *lastname = NULL; + int index = 1; + int foundname = 0; + + if (getifaddrs (&ifaddrs) == -1) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); + return -1; + } + + lastname = ifaddrs->ifa_name; + for (i = ifaddrs; i != NULL; i = i->ifa_next) + { + if (strcmp (lastname, ifaddrs->ifa_name) != 0) + { + lastname = ifaddrs->ifa_name; + index++; + } + if (strcmp (ifname, ifaddrs->ifa_name) == 0) + { + foundname = 1; + break; + } + } + + if (!foundname) + JCL_ThrowException (env, SOCKET_EXCEPTION, + "no interface with that name"); + + freeifaddrs (ifaddrs); + + return index; +#else + (void) ifname; + JCL_ThrowException (env, "java/lang/InternalError", + "getifaddrs not available"); + return -1; +#endif /* HAVE_GETIFADDRS */ +} Index: native/jni/java-net/java_net_VMNetworkInterface.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/java-net/java_net_VMNetworkInterface.c,v retrieving revision 1.3 diff -u -r1.3 java_net_VMNetworkInterface.c --- native/jni/java-net/java_net_VMNetworkInterface.c 12 Jan 2006 09:37:31 -0000 1.3 +++ native/jni/java-net/java_net_VMNetworkInterface.c 17 Sep 2006 06:17:15 -0000 @@ -35,9 +35,15 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ -/* do not move; needed here because of some macro definitions */ +#ifdef HAVE_CONFIG_H #include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include +#include +#include #include #include #include @@ -47,19 +53,197 @@ #include "java_net_VMNetworkInterface.h" -#include "javanet.h" + +static jmethodID java_net_VMNetworkInterface_init; +static jmethodID java_net_VMNetworkInterface_addAddress; + +/* + * Initialize our static method ID's. + * + * Class: java_net_VMNetworkInterface + * Method: initIds + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_java_net_VMNetworkInterface_initIds (JNIEnv *env, jclass clazz) +{ + java_net_VMNetworkInterface_init = + (*env)->GetMethodID (env, clazz, "", "(Ljava/lang/String;)V"); + if (java_net_VMNetworkInterface_init == NULL) + { + if (!(*env)->ExceptionCheck (env)) + JCL_ThrowException (env, "java/lang/NoSuchMethodError", + "VMNetworkinterface.addAddress"); + return; + } + java_net_VMNetworkInterface_addAddress = + (*env)->GetMethodID (env, clazz, "addAddress", "(Ljava/nio/ByteBuffer;)V"); + if (java_net_VMNetworkInterface_addAddress == NULL) + { + if (!(*env)->ExceptionCheck (env)) + JCL_ThrowException (env, "java/lang/NoSuchMethodError", + "VMNetworkinterface.addAddress"); + } +} + +struct netif_entry +{ + char *name; + jobject netif; + int numaddrs; + struct netif_entry *next; +}; + +static void +free_netif_list (JNIEnv *env, struct netif_entry *list) +{ + while (list != NULL) + { + struct netif_entry *e = list->next; + JCL_free (env, list); + list = e; + } +} /* - * Returns all local network interfaces as vector + * Returns all local network interfaces as an array. */ -JNIEXPORT jobject JNICALL -Java_java_net_VMNetworkInterface_getInterfaces (JNIEnv * env, - jclass class - __attribute__ ((__unused__))) +JNIEXPORT jobjectArray JNICALL +Java_java_net_VMNetworkInterface_getVMInterfaces (JNIEnv * env, jclass clazz) { - JCL_ThrowException (env, IO_EXCEPTION, - "java.net.VMNetworkInterface.getInterfaces(): not implemented"); - return 0; +#ifdef HAVE_GETIFADDRS + struct ifaddrs *ifaddrs, *i; + struct netif_entry *iflist = NULL, *e; + jobjectArray netifs; + int numifs = 0; + int k; + + if (getifaddrs (&ifaddrs) == -1) + { + JCL_ThrowException (env, "java/net/SocketException", strerror (errno)); + return NULL; + } + + for (i = ifaddrs; i != NULL; i = i->ifa_next) + { + if (iflist == NULL) + { + iflist = JCL_malloc (env, sizeof (struct netif_entry)); + if (iflist == NULL) + { + freeifaddrs (ifaddrs); + return NULL; + } + iflist->name = i->ifa_name; + iflist->numaddrs = 0; + iflist->next = NULL; + iflist->netif = (*env)->NewObject (env, clazz, java_net_VMNetworkInterface_init, + (*env)->NewStringUTF (env, i->ifa_name)); + if (iflist->netif == NULL) + { + freeifaddrs (ifaddrs); + JCL_free (env, iflist); + return NULL; + } + e = iflist; + } + else + { + struct netif_entry *p = NULL; + for (e = iflist; e != NULL; e = e->next) + { + if (strcmp (e->name, i->ifa_name) == 0) + break; + p = e; + } + + if (e == NULL) + { + p->next = (struct netif_entry *) JCL_malloc (env, sizeof (struct netif_entry)); + if (p->next == NULL) + { + free_netif_list (env, iflist); + freeifaddrs (ifaddrs); + return NULL; + } + e = p->next; + e->name = i->ifa_name; + e->numaddrs = 0; + e->next = NULL; + e->netif = (*env)->NewObject (env, clazz, java_net_VMNetworkInterface_init, + (*env)->NewStringUTF (env, i->ifa_name)); + if (e->netif == NULL) + { + free_netif_list (env, iflist); + freeifaddrs (ifaddrs); + return NULL; + } + } + } + + if (i->ifa_addr == NULL) + continue; + + if (i->ifa_addr->sa_family == AF_INET) + { + struct sockaddr_in *sin = (struct sockaddr_in *) i->ifa_addr; + jobject buffer = (*env)->NewDirectByteBuffer (env, &(sin->sin_addr.s_addr), 4); + (*env)->CallVoidMethod (env, e->netif, java_net_VMNetworkInterface_addAddress, + buffer); + if ((*env)->ExceptionCheck (env)) + { + free_netif_list (env, iflist); + freeifaddrs (ifaddrs); + return NULL; + } + (*env)->DeleteLocalRef (env, buffer); + e->numaddrs++; + } +#ifdef HAVE_INET6 + else if (i->ifa_addr->sa_family == AF_INET6) + { + struct sockaddr_in6 *sin = (struct sockaddr_in6 *) i->ifa_addr; + jobject buffer = (*env)->NewDirectByteBuffer (env, &(sin->sin6_addr.s6_addr), 16); + (*env)->CallVoidMethod (env, e->netif, java_net_VMNetworkInterface_addAddress, + buffer); + if ((*env)->ExceptionCheck (env)) + { + free_netif_list (env, iflist); + freeifaddrs (ifaddrs); + return NULL; + } + (*env)->DeleteLocalRef (env, buffer); + e->numaddrs++; + } +#endif /* HAVE_INET6 */ + } + + /* Count how many interfaces we have that have addresses. */ + for (e = iflist; e != NULL; e = e->next) + { + if (e->numaddrs != 0) + numifs++; + } + + netifs = (*env)->NewObjectArray (env, numifs, clazz, NULL); + k = 0; + for (e = iflist; e != NULL && k < numifs; e = e->next) + { + if (e->numaddrs != 0) + { + (*env)->SetObjectArrayElement (env, netifs, k, e->netif); + (*env)->DeleteLocalRef (env, e->netif); + k++; + } + } + + free_netif_list (env, iflist); + freeifaddrs (ifaddrs); + return netifs; +#else + JCL_ThrowException (env, "java/net/SocketException", "getifaddrs not supported"); + return NULL; +#endif /* HAVE_GETIFADDRS */ } /* end of file */ Index: native/jni/java-nio/Makefile.am =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/java-nio/Makefile.am,v retrieving revision 1.24 diff -u -r1.24 Makefile.am --- native/jni/java-nio/Makefile.am 21 Aug 2006 23:34:46 -0000 1.24 +++ native/jni/java-nio/Makefile.am 17 Sep 2006 06:17:15 -0000 @@ -3,11 +3,11 @@ libjavanio_la_SOURCES = gnu_java_nio_VMPipe.c \ gnu_java_nio_VMChannel.c \ gnu_java_nio_VMSelector.c \ - gnu_java_nio_channels_FileChannelImpl.c \ gnu_java_nio_charset_iconv_IconvDecoder.c \ gnu_java_nio_charset_iconv_IconvEncoder.c \ java_nio_MappedByteBufferImpl.c \ - java_nio_VMDirectByteBuffer.c + java_nio_VMDirectByteBuffer.c \ + gnu_java_nio_KqueueSelectorImpl.c libjavanio_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo \ $(top_builddir)/native/jni/native-lib/libclasspathnative.la \ Index: native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c =================================================================== RCS file: native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c diff -N native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c 17 Sep 2006 06:17:15 -0000 @@ -0,0 +1,361 @@ +/* gnu_java_nio_channel_KqueueSelectorImpl.c -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a 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 of the License, 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; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, 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. */ + + +#if HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#if HAVE_SYS_EVENT_H +#include +#endif /* HAVE_SYS_EVENT_H */ +#include +#include +#include +#include + +#include +#include + +#include + +#define KEY_OP_ACCEPT 16 +#define KEY_OP_CONNECT 8 +#define KEY_OP_READ 1 +#define KEY_OP_WRITE 4 + +/* XXX this requires -std=gnu99 or c99 */ +/* #ifdef TRACE_KQUEUE */ +/* #define TRACE(fmt, ...) fprintf (stderr, "%s: " fmt "\n", __FUNCTION__, __VA_ARGS__); */ +/* #else */ +/* #define TRACE(fmt, ...) */ +/* #endif */ + + +#define throw_not_supported(env) JCL_ThrowException (env, "java/lang/UnsupportedOperationException", "kqueue/kevent support not available") + + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: kqueue_supported + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL +Java_gnu_java_nio_KqueueSelectorImpl_kqueue_1supported (JNIEnv *env __attribute__((unused)), + jclass clazz __attribute__((unused))) +{ +#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT) + return JNI_TRUE; +#else + return JNI_FALSE; +#endif /* HAVE_KQUEUE && HAVE_KEVENT */ +} + + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: sizeof_struct_kevent + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_KqueueSelectorImpl_sizeof_1struct_1kevent +(JNIEnv *env __attribute__((unused)), jclass clazz __attribute__((unused))) +{ +#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT) +/* TRACE("return sizeof %lu", sizeof (struct kevent)); */ + return sizeof (struct kevent); +#else + throw_not_supported (env); + return -1; +#endif /* HAVE_KQUEUE && HAVE_KEVENT */ +} + + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: implOpen + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_KqueueSelectorImpl_implOpen +(JNIEnv *env, jclass clazz __attribute__((unused))) +{ +#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT) + int kq = kqueue (); +/* TRACE("kqueue returns %d", kq); */ + if (kq == -1) + JCL_ThrowException (env, "java/io/IOException", strerror (errno)); + return kq; +#else + throw_not_supported (env); + return -1; +#endif +} + + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: implClose + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_KqueueSelectorImpl_implClose (JNIEnv *env, + jclass clazz __attribute__((unused)), + jint kq) +{ +#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT) +/* TRACE("closing %d", kq); */ + if (close (kq) != 0) + JCL_ThrowException (env, "java/io/IOException", strerror (errno)); +#else + (void) kq; + throw_not_supported (env); +#endif /* HAVE_KQUEUE && HAVE_KEVENT */ +} + + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: kevent_set + * Signature: (Ljava/nio/ByteBuffer;IIIZ)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_KqueueSelectorImpl_kevent_1set (JNIEnv *env, + jclass clazz __attribute__((unused)), + jobject nstate, jint fd, + jint ops, jint key, jboolean delete) +{ +#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT) + struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate); + short ident = kev->ident; + + if (fd != 0) + ident = fd; + + if ((ops & KEY_OP_READ) || (ops & KEY_OP_ACCEPT)) + { + /* Add the event if we never added it before. */ + if (kev[0].flags == 0 && JNI_FALSE == delete) + EV_SET(&kev[0], ident, EVFILT_READ, EV_ADD, 0, 0, (void *) key); + /* Otherwise, delete or reenable it. */ + else if (kev[0].flags != 0) + EV_SET(&kev[0], ident, EVFILT_READ, (JNI_TRUE == delete) ? EV_DELETE : EV_ENABLE, + 0, 0, (void *) key); + } + else + { + /* Means we've added this event before, and need to disable it. */ + if (kev[0].flags != 0) + EV_SET(&kev[0], ident, EVFILT_READ, EV_DISABLE, 0, 0, (void *) key); + } + + /* Do the same thing for the write filter. */ + if ((ops & KEY_OP_WRITE) || (ops & KEY_OP_CONNECT)) + { + if (kev[1].flags == 0 && JNI_FALSE == delete) + EV_SET(&kev[1], ident, EVFILT_WRITE, EV_ADD, 0, 0, (void *) key); + else if (kev[1].flags != 0) + EV_SET(&kev[1], ident, EVFILT_WRITE, (JNI_TRUE == delete) ? EV_DELETE : EV_ENABLE, + 0, 0, (void *) key); + } + else + { + if (kev[1].flags != 0) + EV_SET(&kev[1], ident, EVFILT_WRITE, EV_DISABLE, 0, 0, (void *) key); + } +#else + (void) nstate; + (void) fd; + (void) ops; + (void) key; + (void) delete; + throw_not_supported (env); +#endif /* HAVE_KQUEUE && HAVE_KEVENT */ +} + + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: kevent + * Signature: (ILjava/nio/ByteBuffer;IJ)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_KqueueSelectorImpl_kevent (JNIEnv *env, + jobject this __attribute__((unused)), + jint kq, jobject nstate, jint nevents, + jlong timeout) +{ +#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT) + struct timespec tv; + struct timespec *t = NULL; + struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate); + int ret; + +#ifdef TRACE_KQUEUE + int i; + for (i = 0; i < nevents; i++) + { + printf ("kevent [%d]: ident:%u filter:%x flags:%o fflags:%o data:%p udata:%p\n", + i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, kev[i].fflags, + (void *) kev[i].data, kev[i].udata); + } +#endif + +/* TRACE("events: %p; nevents: %d; timeout: %lld", (void *) kev, nevents, timeout); */ + + if (timeout != -1) + { + tv.tv_sec = timeout / 1000; + tv.tv_nsec = (timeout % 1000) * 1000; + t = &tv; + } + + ret = kevent (kq, (const struct kevent *) kev, nevents, kev, nevents, t); + + if (ret == -1) + { + if (errno == EINTR) + ret = 0; + else + JCL_ThrowException (env, "java/io/IOException", strerror (errno)); + } + +#ifdef TRACE_KQUEUE + for (i = 0; i < ret; i++) + { + printf ("kevent [%d]: ident:%u filter:%x flags:%o fflags:%o data:%p udata:%p\n", + i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, kev[i].fflags, + (void *) kev[i].data, kev[i].udata); + } +#endif + + return ret; +#else + (void) kq; + (void) nstate; + (void) nevents; + (void) timeout; + throw_not_supported (env); + return -1; +#endif /* HAVE_KQUEUE && HAVE_KEVENT */ +} + + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: fetch_key + * Signature: (Ljava/nio/ByteBuffer;)I; + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_KqueueSelectorImpl_fetch_1key (JNIEnv *env, + jclass clazz __attribute__((unused)), + jobject nstate) +{ +#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT) + struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate); +/* TRACE("return key %p\n", kev->udata); */ + return (jint) kev->udata; +#else + (void) nstate; + throw_not_supported (env); + return -1; +#endif /* HAVE_KQUEUE && HAVE_KEVENT */ +} + + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: ready_ops + * Signature: (Ljava/nio/ByteBuffer;I)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_KqueueSelectorImpl_ready_1ops (JNIEnv *env, + jclass clazz __attribute__((unused)), + jobject nstate, jint interest) +{ +#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT) + struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate); + jint ready = 0; + + /* We poll for READ for OP_READ and OP_ACCEPT. */ + if (kev->filter == EVFILT_READ) + { + ready = (interest & KEY_OP_READ) | (interest & KEY_OP_ACCEPT); +/* TRACE("filter EVFILT_READ. Ready ops set to %x", ready); */ + } + + /* Poll for WRITE for OP_WRITE and OP_CONNECT; I guess we *should* + get a WRITE event if we are connected, but I don't know if we do + for real. FIXME */ + if (kev->filter == EVFILT_WRITE) + { + ready = (interest & KEY_OP_WRITE) | (interest & KEY_OP_CONNECT); +/* TRACE("filter EVFILT_WRITE. Ready ops set to %x", ready); */ + } + + return ready; +#else + (void) nstate; + (void) interest; + throw_not_supported (env); + return -1; +#endif /* HAVE_KQUEUE && HAVE_KEVENT */ +} + + +/* + * Class: gnu_java_nio_KqueueSelectorImpl + * Method: check_eof + * Signature: (Ljava/nio/ByteBuffer;)Z + */ +JNIEXPORT jboolean JNICALL +Java_gnu_java_nio_KqueueSelectorImpl_check_1eof (JNIEnv *env, + jclass clazz __attribute__((unused)), + jobject nstate) +{ +#if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT) + struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate); + if ((kev->flags & EV_EOF) == EV_EOF) + return JNI_TRUE; + return JNI_FALSE; +#else + (void) nstate; + throw_not_supported (env); + return JNI_FALSE; +#endif +} Index: native/jni/java-nio/gnu_java_nio_VMChannel.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/java-nio/gnu_java_nio_VMChannel.c,v retrieving revision 1.2 diff -u -r1.2 gnu_java_nio_VMChannel.c --- native/jni/java-nio/gnu_java_nio_VMChannel.c 20 May 2006 15:20:52 -0000 1.2 +++ native/jni/java-nio/gnu_java_nio_VMChannel.c 17 Sep 2006 06:17:15 -0000 @@ -36,25 +36,43 @@ exception statement from your version. */ +#ifdef HAVE_CONFIG_H #include +#endif + +#include +#include +#include +#include +#include +#include + +#include + #include #include #include -#include #include #include #include #include "gnu_java_nio_VMChannel.h" +#include "javanio.h" #ifdef HAVE_FCNTL_H #include #endif /* HAVE_FCNTL_H */ #define IO_EXCEPTION "java/io/IOException" +#define INTERRUPTED_IO_EXCEPTION "java/io/InterruptedIOException" #define NON_READABLE_CHANNEL_EXCEPTION "java/nio/channels/NonReadableChannelException" #define NON_WRITABLE_CHANNEL_EXCEPTION "java/nio/channels/NonWritableChannelException" +#define SOCKET_TIMEOUT_EXCEPTION "java/net/SocketTimeoutException" + +/* Align a value up or down to a multiple of the pagesize. */ +#define ALIGN_DOWN(p,s) ((p) - ((p) % (s))) +#define ALIGN_UP(p,s) ((p) + ((s) - ((p) % (s)))) /* * Limit to maximum of 16 buffers @@ -66,7 +84,7 @@ { #endif -enum JCL_buffer_type { DIRECT, ARRAY, UNKNOWN }; +enum JCL_buffer_type { DIRECT, HEAP, ARRAY, UNKNOWN }; struct JCL_buffer { @@ -98,6 +116,7 @@ const char *sig) { jmethodID mid = (*env)->GetMethodID(env, clazz, name, sig); +/* NIODBG("name: %s; sig: %s", name, sig); */ if (mid == NULL) { JCL_ThrowException(env, "java/lang/InternalError", name); @@ -107,18 +126,19 @@ return mid; } -void +inline void JCL_print_buffer(JNIEnv *env __attribute__((__unused__)), struct JCL_buffer *buf) { - fprintf(stdout, "Buffer - type: %d, ptr: %p\n", buf->type, buf->ptr); - fflush(stdout); + fprintf (stderr, "Buffer - type: %d, ptr: %p\n", buf->type, buf->ptr); } int JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf) { - jobject address = (*env)->GetObjectField(env, bbuf, address_fid); + void *addr = (*env)->GetDirectBufferAddress (env, bbuf); + +/* NIODBG("buf: %p; bbuf: %p; addr: %p", (void *) buf, bbuf, addr); */ buf->position = (*env)->CallIntMethod(env, bbuf, get_position_mid); buf->limit = (*env)->CallIntMethod(env, bbuf, get_limit_mid); @@ -126,11 +146,10 @@ buf->count = 0; buf->type = UNKNOWN; - if (address != NULL) + if (addr != NULL) { - buf->ptr = (jbyte *) JCL_GetRawData(env, address); + buf->ptr = (jbyte *) addr; buf->type = DIRECT; - (*env)->DeleteLocalRef(env, address); } else { @@ -148,7 +167,12 @@ } else { - return -1; + jobject address = (*env)->GetObjectField (env, bbuf, address_fid); + if (address == NULL) + return -1; /* XXX handle non-array, non-native buffers? */ + buf->ptr = (jbyte *) JCL_GetRawData(env, address); + buf->type = HEAP; + (*env)->DeleteLocalRef(env, address); } } @@ -160,6 +184,8 @@ jint action) { jbyteArray arr; + +/* NIODBG("buf: %p; bbuf: %p; action: %x", (void *) buf, bbuf, action); */ /* Set the position to the appropriate value */ if (buf->count > 0) @@ -173,6 +199,7 @@ switch (buf->type) { case DIRECT: + case HEAP: break; case ARRAY: arr = (*env)->CallObjectMethod(env, bbuf, array_mid); @@ -194,6 +221,9 @@ jlong num_bytes) { jint i; + +/* NIODBG("bi_list: %p; vec_len: %d; bbufs: %p; offset: %d; num_bytes: %lld", */ +/* (void *) bi_list, vec_len, bbufs, offset, num_bytes); */ /* Update all of the bbufs with the approriate information */ for (i = 0; i < vec_len; i++) @@ -217,13 +247,57 @@ } +/* + * Class: gnu_java_nio_VMChannel + * Method: stdin_fd + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_stdin_1fd (JNIEnv *env __attribute__((unused)), + jclass c __attribute__((unused))) +{ +/* NIODBG("%d", fileno (stdin)); */ + return fileno (stdin); +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: stdout_fd + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_stdout_1fd (JNIEnv *env __attribute__((unused)), + jclass c __attribute__((unused))) +{ +/* NIODBG("%d", fileno (stdout)); */ + return fileno (stdout); +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: stderr_fd + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_stderr_1fd (JNIEnv *env __attribute__((unused)), + jclass c __attribute__((unused))) +{ +/* NIODBG("%d", fileno (stderr)); */ + return fileno (stderr); +} + + JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_initIDs (JNIEnv *env, jclass clazz __attribute__ ((__unused__))) { jclass bufferClass = JCL_FindClass(env, "java/nio/Buffer"); jclass byteBufferClass = JCL_FindClass(env, "java/nio/ByteBuffer"); - + +/* NIODBG("%s", "..."); */ + address_fid = (*env)->GetFieldID(env, bufferClass, "address", "Lgnu/classpath/Pointer;"); if (address_fid == NULL) @@ -252,6 +326,8 @@ { int opts; +/* NIODBG("fd: %d; blocking: %d", fd, blocking); */ + opts = fcntl(fd, F_GETFL); if (opts < 0) { @@ -260,10 +336,10 @@ return; } - if (blocking) - opts |= O_NONBLOCK; - else + if (blocking == JNI_TRUE) opts &= ~(O_NONBLOCK); + else + opts |= O_NONBLOCK; opts = fcntl(fd, F_SETFL, opts); @@ -277,14 +353,17 @@ JNIEXPORT jint JNICALL -Java_gnu_java_nio_VMChannel_read (JNIEnv *env, - jobject o __attribute__ ((__unused__)), - jint fd, - jobject bbuf) +Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2 (JNIEnv *env, + jobject o __attribute__ ((__unused__)), + jint fd, + jobject bbuf) { +#ifdef HAVE_READ jint len; ssize_t result; struct JCL_buffer buf; + +/* NIODBG("fd: %d; bbuf: %p", fd, bbuf); */ if (JCL_init_buffer(env, &buf, bbuf) < 0) { @@ -292,14 +371,22 @@ JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed"); return -1; } - + len = buf.limit - buf.position; + + if (len == 0) + { + JCL_release_buffer (env, &buf, bbuf, JNI_ABORT); + return 0; + } - result = read(fd, &(buf.ptr[buf.position + buf.offset]), len); - buf.count = result; + result = cpnio_read (fd, &(buf.ptr[buf.position + buf.offset]), len); if (result == 0) - result = -1; /* End Of File */ + { + result = -1; + buf.count = 0; + } else if (result == -1) { buf.count = 0; @@ -311,7 +398,13 @@ JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION, strerror(errno)); return -1; - } + } + else if (EINTR == errno) /* read interrupted */ + { + JCL_release_buffer(env, &buf, bbuf, JNI_ABORT); + JCL_ThrowException(env, INTERRUPTED_IO_EXCEPTION, strerror (errno)); + return -1; + } else { JCL_release_buffer(env, &buf, bbuf, JNI_ABORT); @@ -320,21 +413,31 @@ } } else - - JCL_release_buffer(env, &buf, bbuf, JNI_COMMIT); + buf.count = result; + + JCL_release_buffer(env, &buf, bbuf, 0); return result; +#else + (void) fd; + (void) bbuf; + JCL_ThrowException (env, IO_EXCEPTION, "read not supported"); + return -1; +#endif /* HAVE_READ */ } JNIEXPORT jint JNICALL -Java_gnu_java_nio_VMChannel_write (JNIEnv *env, - jobject o __attribute__ ((__unused__)), - jint fd, - jobject bbuf) +Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2 (JNIEnv *env, + jobject o __attribute__ ((__unused__)), + jint fd, + jobject bbuf) { +#ifdef HAVE_WRITE jint len; ssize_t result; struct JCL_buffer buf; + +/* NIODBG("fd: %d; bbuf: %p", fd, bbuf); */ if (JCL_init_buffer(env, &buf, bbuf) < 0) { @@ -342,16 +445,24 @@ JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed"); return -1; } - + len = buf.limit - buf.position; + + if (len == 0) + { + JCL_release_buffer (env, &buf, bbuf, JNI_ABORT); + return 0; + } - result = write(fd, &(buf.ptr[buf.position + buf.offset]), len); + result = cpnio_write (fd, &(buf.ptr[buf.position + buf.offset]), len); buf.count = result; - + if (result == -1) { if (errno == EAGAIN) /* Non-blocking */ + { result = 0; + } else { JCL_release_buffer(env, &buf, bbuf, JNI_ABORT); @@ -362,7 +473,13 @@ JCL_release_buffer(env, &buf, bbuf, JNI_ABORT); - return result; + return result; +#else + (void) fd; + (void) bbuf; + JCL_ThrowException (env, IO_EXCEPTION, "write not supported"); + return -1; +#endif /* HAVE_WRITE */ } @@ -390,7 +507,10 @@ struct JCL_buffer bi_list[JCL_IOV_MAX]; ssize_t result; jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX; - jlong bytes_read = 0; + jlong bytes_read = 0; + +/* NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */ +/* fd, bbufs, offset, length); */ /* Build the vector of buffers to read into */ for (i = 0; i < vec_len; i++) @@ -401,7 +521,9 @@ buf = &bi_list[i]; bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i); - JCL_init_buffer(env, buf, bbuf); + JCL_init_buffer(env, buf, bbuf); + +/* JCL_print_buffer (env, buf); */ buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]); buffers[i].iov_len = buf->limit - buf->position; @@ -409,7 +531,7 @@ } /* Work the scattering magic */ - result = readv(fd, buffers, vec_len); + result = cpnio_readv (fd, buffers, vec_len); bytes_read = (jlong) result; /* Handle the response */ @@ -442,6 +564,7 @@ return (jlong) result; } + /* * Implementation of a gathering write. Will use the appropriate * vector based read call (currently readv on Linux). @@ -468,6 +591,8 @@ jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX; jlong bytes_written; +/* NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */ +/* fd, bbufs, offset, length); */ /* Build the vector of buffers to read into */ for (i = 0; i < vec_len; i++) @@ -480,13 +605,15 @@ JCL_init_buffer(env, buf, bbuf); +/* JCL_print_buffer(env, buf); */ + buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]); buffers[i].iov_len = buf->limit - buf->position; (*env)->DeleteLocalRef(env, bbuf); } /* Work the gathering magic */ - result = writev(fd, buffers, vec_len); + result = cpnio_writev (fd, buffers, vec_len); bytes_written = (jlong) result; if (result < 0) @@ -518,6 +645,1150 @@ } +/* + * Class: gnu_java_nio_VMChannel + * Method: receive + * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_receive (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jobject dst, jobject addrPort) +{ +#ifdef HAVE_RECVFROM + char *addrPortPtr = (*env)->GetDirectBufferAddress (env, addrPort); + struct JCL_buffer buf; +#ifdef HAVE_INET6 + struct sockaddr_in6 sock_storage; + struct sockaddr_in6 *sock6; + socklen_t slen = sizeof (struct sockaddr_in6); +#else + struct sockaddr_in sock_storage; + socklen_t slen = sizeof (struct sockaddr_in); +#endif /* HAVE_INET6 */ + struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage; + struct sockaddr_in *sock4; + int ret; + jint result = -1; + + if (JCL_init_buffer (env, &buf, dst) == -1) + JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed"); + + ret = cpnio_recvfrom (fd, &(buf.ptr[buf.position + buf.offset]), + buf.limit - buf.position, MSG_WAITALL, + sockaddr, &slen); + + if (-1 == ret) + { + JCL_release_buffer (env, &buf, dst, JNI_ABORT); + if (EINTR == errno) + JCL_ThrowException (env, "java/io/InterruptedIOException", strerror (errno)); + else if (EAGAIN == errno) + { + /* If the socket is in blocking mode, our timeout expired. */ + int val = fcntl (fd, F_GETFL, 0); + if (val == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + else if ((val & O_NONBLOCK) == 0) + JCL_ThrowException (env, "java/net/SocketTimeoutException", + "read timed out"); + } + else + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return 0; + } + + if (sockaddr->sa_family == AF_INET) + { + sock4 = (struct sockaddr_in *) sockaddr; + memcpy (addrPortPtr, &(sock4->sin_addr.s_addr), 4); + ;memcpy (addrPortPtr + 4, &(sock4->sin_port), 2); + result = 4; + } +#ifdef HAVE_INET6 + else if (sockaddr->sa_family == AF_INET6) + { + sock6 = (struct sockaddr_in6 *) sockaddr; + memcpy (addrPortPtr, &(sock6->sin6_addr.s6_addr), 16); + memcpy (addrPortPtr + 16, &(sock6->sin6_port), 2); + result = 16; + } +#endif /* HAVE_INET6 */ + else if (ret == 0) + { + result = 0; + } + else + { + JCL_ThrowException (env, "java/net/SocketException", + "unsupported address type returned"); + } + + buf.count += ret; + JCL_release_buffer (env, &buf, dst, 0); + return result; +#else + (void) fd; + (void) dst; + (void) addrPort; + JCL_ThrowException (env, IO_EXCEPTION, "recvfrom not supported"); +#endif /* HAVE_RECVFROM */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: send + * Signature: (Ljava/nio/ByteBuffer;[BI)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_send (JNIEnv *env, + jclass c __attribute__((unused)), + int fd, jobject src, jbyteArray addr, jint port) +{ +#ifdef HAVE_SENDTO + struct sockaddr_in sockaddr; + jbyte *elems; + struct JCL_buffer buf; + int ret; + +/* NIODBG("fd: %d; src: %p; addr: %p; port: %d", */ +/* fd, src, addr, port); */ + + if (JCL_init_buffer (env, &buf, src) == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed"); + return -1; + } + +/* JCL_print_buffer (env, &buf); */ + + elems = (*env)->GetByteArrayElements (env, addr, NULL); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_addr.s_addr = *((uint32_t *) elems); + sockaddr.sin_port = htons (port); + + do + { + ret = cpnio_sendto (fd, &(buf.ptr[buf.position + buf.offset]), + buf.limit - buf.position, + 0, (const struct sockaddr *) &sockaddr, + sizeof (struct sockaddr_in)); + } + while (-1 == ret && EINTR == errno); + + (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT); + + if (-1 == ret) + { + if (errno != EAGAIN) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + JCL_release_buffer (env, &buf, src, JNI_ABORT); + return 0; + } + + buf.count += ret; + JCL_release_buffer (env, &buf, src, JNI_ABORT); + return ret; +#else + (void) fd; + (void) src; + (void) addr; + (void) port; +#endif /* HAVE_SENDTO */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: send6 + * Signature: (Ljava/nio/ByteBuffer;[BI)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_send6 (JNIEnv *env, + jclass c __attribute__((unused)), + int fd, jobject src, jbyteArray addr, jint port) +{ +#if defined(HAVE_SENDTO) && defined(HAVE_INET6) + struct sockaddr_in6 sockaddr; + jbyte *elems; + struct JCL_buffer buf; + int ret; + +/* NIODBG("fd: %d; src: %p; addr: %p; port: %d", */ +/* fd, src, addr, port); */ + + if (JCL_init_buffer (env, &buf, src) == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed"); + return -1; + } + +/* JCL_print_buffer (env, &buf); */ + + elems = (*env)->GetByteArrayElements (env, addr, NULL); + + sockaddr.sin6_family = AF_INET6; + memcpy (&sockaddr.sin6_addr.s6_addr, elems, 16); + sockaddr.sin6_port = htons (port); + + do + { + ret = cpnio_sendto (fd, (const void *) (buf.ptr + buf.offset), + buf.limit - buf.position, + 0, (const struct sockaddr *) &sockaddr, + sizeof (struct sockaddr_in6)); + } + while (-1 == ret && EINTR == errno); + + (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT); + + if (-1 == ret) + { + if (errno != EAGAIN) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + JCL_release_buffer (env, &buf, src, JNI_ABORT); + return 0; + } + + buf.count += ret; + JCL_release_buffer (env, &buf, src, JNI_ABORT); + return ret; +#else + (void) fd; + (void) src; + (void) addr; + (void) port; + JCL_ThrowException (env, IO_EXCEPTION, "IPv6 sendto not supported"); + return -1; +#endif /* HAVE_SENDTO && HAVE_INET6 */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: read + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_read__I (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd) +{ +#ifdef HAVE_READ + char in; + int ret; + +/* NIODBG("fd: %d", fd); */ + + ret = cpnio_read (fd, &in, 1); + if (-1 == ret) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + if (0 == ret) + return -1; + + return (in & 0xFF); +#else + (void) fd; + JCL_ThrowException (env, IO_EXCEPTION, "read not supported"); +#endif /* HAVE_READ */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: write + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_VMChannel_write__II (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jint data) +{ +#ifdef HAVE_WRITE + char out = (char) data; + int ret; + +/* NIODBG("fd: %d; data: %d", fd, data); */ + + ret = cpnio_write (fd, &out, 1); + + if (-1 == ret) + JCL_ThrowException(env, IO_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) data; + JCL_ThrowException (env, IO_EXCEPTION, "write not supported"); +#endif /* HAVE_WRITE */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: socket + * Signature: (Z)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_socket (JNIEnv *env, jclass clazz __attribute__((unused)), + jboolean stream) +{ +#ifdef HAVE_SOCKET + int ret; + + do + { + ret = cpnio_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0); + } + while (-1 == ret && EINTR == errno); + + if (ret == -1) + JCL_ThrowException (env, "java/net/SocketException", strerror (errno)); +/* NIODBG("created socket %d", ret); */ + + return ret; +#else + (void) stream; + JCL_ThrowException (env, IO_EXCEPTION, "socket not supported"); + return -1; +#endif /* HAVE_SOCKET */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: connect + * Signature: (I[BI)Z + */ +JNIEXPORT jboolean JNICALL +Java_gnu_java_nio_VMChannel_connect (JNIEnv *env, jclass clazz __attribute__((unused)), + jint fd, jbyteArray addr, jint port, jint timeout) +{ +#ifdef HAVE_CONNECT + struct sockaddr_in sockaddr; + struct timeval timeo; + int origflags = 0, flags; + jbyte *addr_elems; + int ret; + + if ((*env)->GetArrayLength (env, addr) != 4) + { + JCL_ThrowException (env, "java/io/IOException", "expecting 4-byte address"); + return JNI_FALSE; + } + + if (timeout > 0) + { + timeo.tv_sec = timeout / 1000; + timeo.tv_usec = (timeout % 1000) * 1000; + origflags = fcntl (fd, F_GETFL, 0); + if (origflags == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + /* Set nonblocking mode, if not already set. */ + if (!(origflags & O_NONBLOCK)) + { + flags = origflags | O_NONBLOCK; + if (fcntl (fd, F_SETFL, flags) == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + } + } + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + + memset (&sockaddr, 0, sizeof (struct sockaddr_in)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons (port); + sockaddr.sin_addr.s_addr = *((uint32_t *) addr_elems); + + + ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr, + sizeof (struct sockaddr_in)); + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + /* If a timeout was specified, select on the file descriptor with + the timeout. */ + if (timeout > 0 && ret == -1) + { + /* Reset the non-blocking flag, if needed. */ + if (!(origflags & O_NONBLOCK)) + { + if (fcntl (fd, F_SETFL, origflags) == -1) + { + /* oops */ + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + } + if (EINPROGRESS == errno) + { + fd_set wrfds; + FD_SET(fd, &wrfds); + ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo); + if (ret == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + if (ret == 0) /* connect timed out */ + { + JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION, + "connect timed out"); + return JNI_FALSE; + } + return JNI_TRUE; /* Connected! */ + } + else if (ECONNREFUSED == errno) + { + JCL_ThrowException (env, "java/net/ConnectException", + strerror (errno)); + return JNI_FALSE; + } + else + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + } + + if (ret == -1) + { + if (EINPROGRESS == errno) + return JNI_FALSE; + else if (ECONNREFUSED == errno) + { + JCL_ThrowException (env, "java/net/ConnectException", + strerror (errno)); + return JNI_FALSE; + } + else + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + } + + return JNI_TRUE; +#else + (void) fd; + (void) addr; + (void) port; + (void) timeout; + JCL_ThrowException (env, IO_EXCEPTION, "connect not supported"); + return JNI_FALSE; +#endif /* HAVE_CONNECT */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: connect6 + * Signature: (I[BI)Z + */ +JNIEXPORT jboolean JNICALL +Java_gnu_java_nio_VMChannel_connect6 (JNIEnv *env, jclass clazz __attribute__((unused)), + jint fd, jbyteArray addr, jint port, int timeout) +{ +#if defined(HAVE_CONNECT) && defined(HAVE_INET6) + struct sockaddr_in6 sockaddr; + struct timeval timeo; + int flags, origflags = 0; + jbyte *addr_elems; + int ret; + + if (timeout > 0) + { + timeo.tv_sec = timeout / 1000; + timeo.tv_usec = (timeout % 1000) * 1000; + origflags = fcntl (fd, F_GETFL, 0); + if (origflags == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + /* Set nonblocking mode, if not already set. */ + if (!(origflags & O_NONBLOCK)) + { + flags = origflags | O_NONBLOCK; + if (fcntl (fd, F_SETFL, flags) == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + } + } + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + + memset (&sockaddr, 0, sizeof (struct sockaddr_in6)); + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = htons (port); + memcpy (&sockaddr.sin6_addr.s6_addr, addr_elems, 16); + + ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr, + sizeof (struct sockaddr_in6)); + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + /* If a timeout was specified, select on the file descriptor with + the timeout. */ + if (timeout > 0 && ret == -1) + { + /* Reset the non-blocking flag, if needed. */ + if (!(origflags & O_NONBLOCK)) + { + if (fcntl (fd, F_SETFL, origflags) == -1) + { + /* oops */ + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + } + if (EINPROGRESS == errno) + { + fd_set wrfds; + FD_SET(fd, &wrfds); + ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo); + if (ret == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + if (ret == 0) /* connect timed out */ + { + JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION, + "connect timed out"); + return JNI_FALSE; + } + return JNI_TRUE; /* Connected! */ + } + else if (ECONNREFUSED == errno) + { + JCL_ThrowException (env, "java/net/ConnectException", + strerror (errno)); + return JNI_FALSE; + } + else + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + } + + if (ret == -1) + { + if (EAGAIN == errno) + return JNI_FALSE; + else if (ECONNREFUSED == errno) + { + JCL_ThrowException (env, "java/net/ConnectException", + strerror (errno)); + return JNI_FALSE; + } + else + { + JCL_ThrowException (env, "java/io/IOException", strerror (errno)); + return JNI_FALSE; + } + } + + return JNI_TRUE; +#else + (void) fd; + (void) addr; + (void) port; + (void) timeout; + JCL_ThrowException (env, IO_EXCEPTION, "IPv6 connect not supported"); + return JNI_FALSE; +#endif /* HAVE_CONNECT && HAVE_INET6 */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: getsockname + * Signature: (ILjava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_getsockname (JNIEnv *env, jclass clazz __attribute__((unused)), + jint fd, jobject name) +{ +#ifdef HAVE_GETSOCKNAME +#ifdef HAVE_INET6 + struct sockaddr_in6 *addr6; + struct sockaddr_in6 sock_storage; + socklen_t socklen = sizeof (struct sockaddr_in6); +#else + struct sockaddr_in sock_storage; + socklen_t socklen = sizeof (struct sockaddr_in); +#endif /* HAVE_INET6 */ + + struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage; + struct sockaddr_in *addr4; + int ret; + char *nameptr = (*env)->GetDirectBufferAddress (env, name); + + ret = getsockname (fd, sockaddr, &socklen); + if (ret == -1) + { + JCL_ThrowException (env, "java/net/SocketException", strerror (errno)); + return 0; + } + + if (sockaddr->sa_family == AF_INET) + { + addr4 = (struct sockaddr_in *) sockaddr; + memcpy (nameptr, &(addr4->sin_addr.s_addr), 4); + memcpy (nameptr + 4, &(addr4->sin_port), 2); + return 4; + } + +#ifdef HAVE_INET6 + /* IPv6 */ + if (sockaddr->sa_family == AF_INET6) + { + addr6 = (struct sockaddr_in6 *) sockaddr; + memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16); + memcpy (nameptr, &(addr6->sin6_port), 2); + return 16; + } +#endif /* HAVE_INET6 */ + JCL_ThrowException (env, IO_EXCEPTION, "unsupported address format"); + return -1; +#else + (void) fd; + (void) name; + JCL_ThrowException (env, IO_EXCEPTION, "getsockname not supported"); + return -1; +#endif /* HAVE_GETSOCKNAME */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: getpeername + * Signature: (ILjava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_getpeername (JNIEnv *env, jclass clazz __attribute__((unused)), + jint fd, jobject name) +{ +#ifdef HAVE_GETPEERNAME +#ifdef HAVE_INET6 + struct sockaddr_in6 *addr6; + struct sockaddr_in6 sock_storage; + socklen_t socklen = sizeof (struct sockaddr_in6); +#else + struct sockaddr_in sock_storage; + socklen_t socklen = sizeof (struct sockaddr_in); +#endif /* HAVE_INET6 */ + + struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage; + struct sockaddr_in *addr4; + int ret; + char *nameptr = (*env)->GetDirectBufferAddress (env, name); + + ret = getpeername (fd, sockaddr, &socklen); + if (ret == -1) + { + if (ENOTCONN != errno) + JCL_ThrowException (env, "java/net/SocketException", strerror (errno)); + return 0; + } + + if (sockaddr->sa_family == AF_INET) + { + addr4 = (struct sockaddr_in *) sockaddr; + memcpy (nameptr, &(addr4->sin_addr.s_addr), 4); + memcpy (nameptr + 4, &(addr4->sin_port), 2); + return 4; + } +#ifdef HAVE_INET6 + else if (sockaddr->sa_family == AF_INET6) + { + addr6 = (struct sockaddr_in6 *) sockaddr; + memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16); + memcpy (nameptr, &(addr6->sin6_port), 2); + return 16; + } +#endif /* HAVE_INET6 */ + + JCL_ThrowException (env, "java/net/SocketException", + "unsupported address type"); + return -1; +#else + (void) fd; + (void) name; + JCL_ThrowException (env, IO_EXCEPTION, "getpeername not supported"); + return -1; +#endif /* HAVE_GETPEERNAME */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: accept + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_accept (JNIEnv *env, + jclass clazz __attribute__((unused)), + jint fd) +{ +#ifdef HAVE_ACCEPT + int ret; + +#ifdef HAVE_INET6 + struct sockaddr_in6 addr; + socklen_t alen = sizeof (struct sockaddr_in6); +#else + struct sockaddr_in addr; + socklen_t alen = sizeof (struct sockaddr_in); +#endif /* HAVE_INET6 */ + + do + { + ret = cpnio_accept (fd, (struct sockaddr *) &addr, &alen); + } + while (ret == -1 && EINTR == errno); + + if (ret == -1) + { + if (EWOULDBLOCK != ret && EAGAIN != ret) + JCL_ThrowException (env, "java/net/SocketException", strerror (errno)); + } + + return ret; +#else + (void) fd; + JCL_ThrowException (env, IO_EXCEPTION, "accept not supported"); + return -1; +#endif /* HAVE_ACCEPT */ +} + + + +/* + * Class: gnu_java_nio_VMChannel + * Method: disconnect + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_VMChannel_disconnect (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd) +{ + struct sockaddr sockaddr; + + sockaddr.sa_family = AF_UNSPEC; + if (connect (fd, &sockaddr, sizeof (struct sockaddr)) == -1) + { + /* The expected error for a successful disconnect is EAFNOSUPPORT. */ + if (errno != EAFNOSUPPORT) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + } +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: close + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_VMChannel_close (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd) +{ + if (close (fd) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: available + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_available (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd) +{ + jint avail = 0; + +/* NIODBG("fd: %d", fd); */ + if (ioctl (fd, FIONREAD, &avail) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); +/* NIODBG("avail: %d", avail); */ + + return avail; +} + + +enum FileChannel_mode { + CPNIO_READ = 1, + CPNIO_WRITE = 2, + CPNIO_APPEND = 4, + CPNIO_EXCL = 8, + CPNIO_SYNC = 16, + CPNIO_DSYNC = 32 +}; + + +/* + * Class: gnu_java_nio_VMChannel + * Method: open + * Signature: (Ljava/lang/String;I)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_open (JNIEnv *env, + jclass c __attribute__((unused)), + jstring path, jint mode) +{ + int nmode = 0; + int ret; + const char *npath; + mode_t mask = umask (0); + umask (mask); + + if ((mode & CPNIO_READ) && (mode & CPNIO_WRITE)) + nmode = O_RDWR; + else if (mode & CPNIO_WRITE) + nmode = O_WRONLY; + else + nmode = O_RDONLY; + + nmode = (nmode + | ((nmode == O_RDWR || nmode == O_WRONLY) ? O_CREAT : 0) + | ((mode & CPNIO_APPEND) ? O_APPEND : + ((nmode == O_RDWR || nmode == O_WRONLY) ? O_TRUNC : 0)) + | ((mode & CPNIO_EXCL) ? O_EXCL : 0) + | ((mode & CPNIO_SYNC) ? O_SYNC : 0)); + + npath = JCL_jstring_to_cstring (env, path); + +/* NIODBG("path: %s; mode: %x", npath, nmode); */ + + ret = open (npath, nmode, 0777 & ~mask); + +/* NIODBG("ret: %d\n", ret); */ + + JCL_free_cstring (env, path, npath); + + if (-1 == ret) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + + return ret; +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: position + * Signature: (I)J + */ +JNIEXPORT jlong JNICALL +Java_gnu_java_nio_VMChannel_position (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd) +{ +#ifdef HAVE_LSEEK + off_t ret; + + ret = lseek (fd, 0, SEEK_CUR); + + if (-1 == ret) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + + return (jlong) ret; +#else + JCL_ThrowException (env, IO_EXCEPTION, "position not supported"); + return -1; +#endif /* HAVE_LSEEK */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: seek + * Signature: (IJ)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_VMChannel_seek (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jlong pos) +{ +#ifdef HAVE_LSEEK + if (lseek (fd, (off_t) pos, SEEK_SET) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); +#else + JCL_ThrowException (env, IO_EXCEPTION, "seek not supported"); +#endif /* HAVE_LSEEK */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: truncate + * Signature: (IJ)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_VMChannel_truncate (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jlong len) +{ +#if defined(HAVE_FTRUNCATE) && defined(HAVE_LSEEK) + off_t pos = lseek (fd, 0, SEEK_CUR); + if (pos == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return; + } + if (ftruncate (fd, (off_t) len) == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return; + } + if (pos > len) + { + if (lseek (fd, len, SEEK_SET) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + } +#else + JCL_ThrowException (env, IO_EXCEPTION, "truncate not supported"); +#endif /* HAVE_FTRUNCATE && HAVE_LSEEK */ +} + + +/* + * Class: gnu_java_nio_VMChannel + * Method: lock + * Signature: (IJJZZ)Z + */ +JNIEXPORT jboolean JNICALL +Java_gnu_java_nio_VMChannel_lock (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jlong pos, jlong len, + jboolean shared, jboolean wait) +{ +#if HAVE_FCNTL + struct flock fl; + + fl.l_start = (off_t) pos; + fl.l_len = (off_t) len; + fl.l_pid = getpid (); + fl.l_type = (shared ? F_RDLCK : F_WRLCK); + fl.l_whence = SEEK_SET; + + if (cpnio_fcntl (fd, (wait ? F_SETLKW : F_SETLK), (int) &fl) == -1) + { + if (errno != EAGAIN) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + + return JNI_TRUE; +#else + JCL_ThrowException (env, IO_EXCEPTION, "lock not supported"); + return JNI_FALSE; +#endif /* HAVE_FCNTL */ +} + +/* + * Class: gnu_java_nio_VMChannel + * Method: unlock + * Signature: (IJJ)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_VMChannel_unlock (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jlong pos, jlong len) +{ +#if HAVE_FCNTL + struct flock fl; + + fl.l_start = (off_t) pos; + fl.l_len = (off_t) len; + fl.l_pid = getpid (); + fl.l_type = F_UNLCK; + fl.l_whence = SEEK_SET; + + if (cpnio_fcntl (fd, F_SETLK, (int) &fl) == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + } +#else + JCL_ThrowException (env, IO_EXCEPTION, "unlock not supported"); +#endif /* HAVE_FCNTL */ +} + +/* + * Class: gnu_java_nio_VMChannel + * Method: size + * Signature: (I)J + */ +JNIEXPORT jlong JNICALL +Java_gnu_java_nio_VMChannel_size (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd) +{ +#ifdef HAVE_FSTAT + struct stat st; + + if (fstat (fd, &st) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + + return (jlong) st.st_size; +#else + JCL_ThrowException (env, IO_EXCEPTION, "size not supported"); + return 0; +#endif +} + +/* + * Class: gnu_java_nio_VMChannel + * Method: map + * Signature: (ICJI)Lgnu/classpath/Pointer; + */ +JNIEXPORT jobject JNICALL +Java_gnu_java_nio_VMChannel_map (JNIEnv *env, + jclass clazz __attribute__((unused)), + jint fd, jchar mode, jlong position, jint size) +{ +#ifdef HAVE_MMAP + jclass MappedByteBufferImpl_class; + jmethodID MappedByteBufferImpl_init = NULL; + jobject Pointer_instance; + volatile jobject buffer; + long pagesize; + int prot, flags; + void *p; + void *address; + +/* NIODBG("fd: %d; mode: %x; position: %lld; size: %d", */ +/* fd, mode, position, size); */ + + /* FIXME: should we just assume we're on an OS modern enough to + have 'sysconf'? And not check for 'getpagesize'? */ +#if defined(HAVE_GETPAGESIZE) + pagesize = getpagesize (); +#elif defined(HAVE_SYSCONF) + pagesize = sysconf (_SC_PAGESIZE); +#else + JCL_ThrowException (env, IO_EXCEPTION, + "can't determine memory page size"); + return NULL; +#endif /* HAVE_GETPAGESIZE/HAVE_SYSCONF */ + + if ((*env)->ExceptionOccurred (env)) + { + return NULL; + } + + prot = PROT_READ; + if (mode == '+' || mode == 'c') + { + /* When writing we need to make sure the file is big enough, + otherwise the result of mmap is undefined. */ + struct stat st; + if (fstat (fd, &st) == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return NULL; + } + if (position + size > st.st_size) + { + if (ftruncate(fd, position + size) == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return NULL; + } + } + prot |= PROT_WRITE; + } + + flags = (mode == 'c' ? MAP_PRIVATE : MAP_SHARED); + p = mmap (NULL, (size_t) ALIGN_UP (size, pagesize), prot, flags, + fd, ALIGN_DOWN (position, pagesize)); + if (p == MAP_FAILED) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return NULL; + } + + /* Unalign the mapped value back up, since we aligned offset + down to a multiple of the page size. */ + address = (void *) ((char *) p + (position % pagesize)); + + Pointer_instance = JCL_NewRawDataObject(env, address); + + MappedByteBufferImpl_class = (*env)->FindClass (env, + "java/nio/MappedByteBufferImpl"); + if (MappedByteBufferImpl_class != NULL) + { + MappedByteBufferImpl_init = + (*env)->GetMethodID (env, MappedByteBufferImpl_class, + "", "(Lgnu/classpath/Pointer;IZ)V"); + } + + if ((*env)->ExceptionOccurred (env)) + { + munmap (p, ALIGN_UP (size, pagesize)); + return NULL; + } + if (MappedByteBufferImpl_init == NULL) + { + JCL_ThrowException (env, "java/lang/InternalError", + "could not get MappedByteBufferImpl constructor"); + munmap (p, ALIGN_UP (size, pagesize)); + return NULL; + } + + buffer = (*env)->NewObject (env, MappedByteBufferImpl_class, + MappedByteBufferImpl_init, Pointer_instance, + (jint) size, mode == 'r'); + return buffer; +#else + (void) fd; + (void) mode; + (void) position; + (void) size; + JCL_ThrowException (env, IO_EXCEPTION, + "memory-mapped files not implemented"); + return 0; +#endif /* HAVE_MMAP */ +} + +/* + * Class: gnu_java_nio_VMChannel + * Method: flush + * Signature: (IZ)Z + */ +JNIEXPORT jboolean JNICALL +Java_gnu_java_nio_VMChannel_flush (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jboolean metadata __attribute__((unused))) +{ +#ifdef HAVE_FSYNC + /* XXX blocking? */ + if (fsync (fd) == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + return JNI_FALSE; + } + return JNI_TRUE; +#else + JCL_ThrowException (env, IO_EXCEPTION, "flush not implemented"); + return JNI_TRUE; +#endif /* HAVE_FSYNC */ +} #ifdef __cplusplus Index: native/jni/java-nio/gnu_java_nio_VMPipe.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/java-nio/gnu_java_nio_VMPipe.c,v retrieving revision 1.6 diff -u -r1.6 gnu_java_nio_VMPipe.c --- native/jni/java-nio/gnu_java_nio_VMPipe.c 25 Jan 2006 10:40:12 -0000 1.6 +++ native/jni/java-nio/gnu_java_nio_VMPipe.c 17 Sep 2006 06:17:15 -0000 @@ -35,8 +35,14 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ + +#ifdef HAVE_CONFIG_H #include +#endif /* HAVE_CONFIG_H */ + #include +#include +#include #include #include @@ -45,12 +51,33 @@ #define IO_EXCEPTION "java/io/IOException" -JNIEXPORT void JNICALL -Java_gnu_java_nio_VMPipe_init (JNIEnv * env, - jclass cls __attribute__ ((__unused__)), - jobject self __attribute__ ((__unused__)), - jobject provider __attribute__ ((__unused__))) +/* + * Class: gnu_java_nio_VMPipe + * Method: pipe0 + * Signature: ()[I + */ +JNIEXPORT jintArray JNICALL +Java_gnu_java_nio_VMPipe_pipe0 (JNIEnv *env, + jclass c __attribute__((unused))) { - JCL_ThrowException (env, IO_EXCEPTION, - "gnu.java.nio.VMPipe.init(): not implemented"); + int fd[2]; + jintArray array; + jint* elem; + int ret; + + /* FIXME: autoconf this? */ + ret = pipe (fd); + + if (ret == -1) + { + JCL_ThrowException (env, "java/io/IOException", strerror (errno)); + return NULL; + } + + array = (*env)->NewIntArray (env, 2); + elem = (*env)->GetIntArrayElements (env, array, NULL); + elem[0] = fd[0]; + elem[1] = fd[1]; + (*env)->ReleaseIntArrayElements (env, array, elem, 0); + return array; } Index: native/jni/java-nio/javanio.c =================================================================== RCS file: native/jni/java-nio/javanio.c diff -N native/jni/java-nio/javanio.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ native/jni/java-nio/javanio.c 17 Sep 2006 06:17:15 -0000 @@ -0,0 +1,122 @@ +/* javanio.c -- implementations of functions in javanio.h. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a 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 of the License, 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; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, 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. */ + + +/* + * Note, because these functions are trivial, and should be inlined, + * we include this file in the header, and do not compile it. + */ + +#include +#include +#include +#include +#include + +extern inline ssize_t +cpnio_read (int fd, void *buf, size_t nbytes) +{ + return read (fd, buf, nbytes); +} + +extern inline ssize_t +cpnio_readv (int fd, const struct iovec *iov, int iovcnt) +{ + return readv (fd, iov, iovcnt); +} + +extern inline ssize_t +cpnio_write (int fd, const void *buf, size_t nbytes) +{ + return write (fd, buf, nbytes); +} + +extern inline ssize_t +cpnio_writev (int fd, const struct iovec *iov, size_t iovcnt) +{ + return writev (fd, iov, iovcnt); +} + +extern inline int +cpnio_socket (int domain, int type, int protocol) +{ + return socket (domain, type, protocol); +} + +extern inline int +cpnio_connect (int fd, const struct sockaddr *addr, socklen_t addrlen) +{ + return connect (fd, addr, addrlen); +} + +extern inline int +cpnio_accept (int fd, struct sockaddr *addr, socklen_t *addrlen) +{ + return accept (fd, addr, addrlen); +} + +extern inline ssize_t +cpnio_sendto (int fd, const void *msg, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + return sendto (fd, msg, len, flags, to, tolen); +} + +extern inline ssize_t +cpnio_recvfrom (int fd, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + return recvfrom (fd, buf, len, flags, from, fromlen); +} + +extern inline int +cpnio_fcntl (int fd, int cmd, int arg) +{ +#ifdef HAVE_FCNTL + return fcntl (fd, cmd, arg); +#else + errno = ENOSUP; + return -1; +#endif /* HAVE_FCNTL */ +} + +extern inline int +cpnio_select (int nfds, fd_set *readfds, fd_set *writefds, + fd_set *excepfds, struct timeval *timeo) +{ + return select (nfds, readfds, writefds, excepfds, timeo); +} Index: native/jni/java-nio/javanio.h =================================================================== RCS file: native/jni/java-nio/javanio.h diff -N native/jni/java-nio/javanio.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ native/jni/java-nio/javanio.h 17 Sep 2006 06:17:15 -0000 @@ -0,0 +1,332 @@ +/* javanio.h -- reference implementation of native functions. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a 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 of the License, 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; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, 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. */ + + +#ifndef __JAVANIO_H__ +#define __JAVANIO_H__ + +/** + * This header defines functions that are called by our JNI reference + * implementation of java.nio.*. In our reference implementation, these + * functions map exactly to their counterparts in POSIX; in implementations + * that can't use these functions directly (such as systems that use user-land + * threads, and thus can't call blocking system calls directly) can provide + * their own implementations suitable for their system. + */ + +/** + * This macro is used in all function prototypes below; if any additional + * keywords need to be added to a prototype, declare them in this macro. + */ +#define CPNIO_EXPORT extern inline + +/** + * Read bytes from the given file descriptor into the given memory address, which + * has sufficient space for NBYTES bytes. + * + * \param fd The file descriptor to read from. + * \param buf The memory address to read bytes into. + * \param nbytes The number of bytes available to store in BUF. + * \return The number of bytes read, possibly zero, on success; return -1 on failure, + * and set ERRNO to an appropriate value. + * \see read(2) + * + * Allowed errno values: + * [EBADF] If FD is not a valid file descriptor, or is not open for reading. + * [EFAULT] If BUF points outside the process's address space. + * [EIO] An I/O error occurrs. + * [EINTR] If the read is interrupted by a signal. + * [EINVAL] If FD is negative. + * [EAGAIN] If FD was marked for non-blocking I/O, and no data were ready to + * be read. + */ +CPNIO_EXPORT ssize_t cpnio_read (int fd, void *buf, size_t nbytes); + +/* + * Read bytes from a file descriptor into a sequence of IO buffers. + * + * The iovec structure is defined as: + * + * struct iovec { + * char *iov_base; + * size_t iov_len; + * }; + * + * The call to _cp_readv should do a scattering read, where for each struct iovec + * in the supplied list, up to IOV_LEN bytes are read into IOV_BASE. The function + * returns the total number of bytes read into all supplied buffers. + * + * \param fd The file descriptor. + * \param iov A pointer to the head of a list of iovec structures. + * \param iovcnt The number of iovec structures pointed to by IOV. + * \return The total number of bytes read accross all buffers, possibly zero. On + * error, -1 is returned and ERRNO is set. + * \see readv(2) + * + * Allowed ERRNO values include all of those listed for _cp_read, as well as the + * following: + * [EINVAL] If IOVCNT overflows the maximum number of iovec structures + * this platform supports (usually 16), if any IOV_LEN value + * is negative, or if the sum of all IOV_LEN values is too + * large to be stored in a ssize_t (usually a 32-bit integer). + * [EFAULT] If part of IOV points outside the process's address space. + */ +CPNIO_EXPORT ssize_t cpnio_readv (int fd, const struct iovec *iov, int iovcnt); + +/* + * Write NBYTES bytes from BUF to the file descriptor FD, returning the number + * of bytes successfully written. + * + * \param fd The file descriptor. + * \param buf A pointer to the bytes to write. + * \param nbytes The maximum number of bytes to write. + * \return The number of bytes written to the file descriptor, possibly zero. -1 + * is returned if an error is encountered, and ERRNO will be set. + * \see write(2) + * + * Allowed ERRNO values: + * [EBADF] If FD is not a valid file descriptor or is not open for writing. + * [EPIPE] If FD is a pipe, when the other side is disconnected; if FD is a + * socket, when the peer is not connected. + * [EFBIG] When FD is a file, and writing to it overflows the process's + * or the system's maximim file size. + * [EFAULT] If the buffer to write points outside the process's address + * space. + * [EINVAL] If the descriptor FD is negative. + * [ENOSPC] If FD is a file, and there is insufficient space on the + * filesystem. + * [EDQUOT] If FD is a file, and the user's disk quota has been exceeded. + * [EIO] If an I/O error occurs. + * [EINTR] If the call is interrupted by a signal. + * [EAGAIN] If FD is in non-blocking mode, and no bytes could be immediately + * written. + */ +CPNIO_EXPORT ssize_t cpnio_write (int fd, const void *buf, size_t nbytes); + +/* + * Write data from a sequence of IOVCNT buffers IOV to a file descriptor FD. + * + * \param fd The file descriptor. + * \param iov The list of buffers to write. + * \param iovcnt The number of iovec structures pointed to by IOV. + * \return The total number of bytes written from the given buffers, possibly + * zero. -1 if an error occurs, and ERRNO will be set. + * \see writev(2) + * + * Allowed ERRNO values include those mentioned in _cp_write, as well as: + * [EDESTADDRREQ] If the descriptor is a datagram socket, and the peer is + * no longer available. + * [EINVAL] If IOVCNT is out of range, if any IOV_LEN value is + * negative, or if the sum of all IOVCNT IOV_LEN values + * will overflow a ssize_t. + * [ENOBUFS] If the mbuf pool is exhausted (???). + */ +CPNIO_EXPORT ssize_t cpnio_writev (int fd, const struct iovec *iov, size_t iovcnt); + +/** + * Open a new, unbound and unconnected socket. + * + * \param domain The socket domain. Implementations need only handle AF_INET. + * \param type The socket type; implementations need only handle types + * SOCK_STREAM (for streaming sockets) and SOCK_DGRAM (for datagram sockets). + * \param protocol This should always be 0. It can be ignored. + * \return A new file descriptor pointing to a newly created socket, or -1 on + * error, and ERRNO set. + * + * Allowed ERRNO values: + * [EPROTONOSUPPORT] If TYPE is unrecognized. + * [EMFILE] If a new file descriptor cannot be allocated, because + * the process's descriptor table is full. + * [ENFILE] Likewise, but when the system table is full. + * [EACCES] If this operation is not allowed. + * [ENOBUFS] If there is not enough buffer space available for the + * new socket. + */ +CPNIO_EXPORT int cpnio_socket (int domain, int type, int protocol); + +/** + * Connect a socket to a remote address. + * + * \param fd The file descriptor of the socket to connect. + * \param addr The address to connect to. In practice, this should be + * either a `struct sockaddr_in' or a `struct sockaddr_in6'. + * \param addrlen The size of the address structure passed by ADDR. + * \return Zero if the connect succeeds. -1 on error, and ERRNO should be set. + * + * Allowed ERRNO values: + * [EBADF] If FD is not a valid file descriptor. + * [ENOTSOCK] If FD is not a socket descriptor. + * [EADDRNOTAVAIL] If ADDR is not available for use to this process. + * [EAFNOSUPPORT] If the address family of ADDR is not supported. + * [EISCONN] If the socket is already connected. + * [ETIMEDOUT] If the connection could not be made in a reasonable + * amount of time. + * [ECONNREFUSED] If the connection attempt was rejected. + * [ENETUNREACH] If the network ADDR is on is unreachable. + * [EADDRINUSE] If the address is already in use. + * [EFAULT] If ADDR points outside the addressable space. + * [EINPROGRESS] If FD is in non-blocking mode, and the connection could + * not be completed immediately. + * [EALREADY] If FD is in non-blocking mode, and a connection attempt + * is still pending. + * [EACCESS] If ADDR is the broadcast address, and the socket option + * SO_BROADCAST is not set. + */ +CPNIO_EXPORT int cpnio_connect (int fd, const struct sockaddr *addr, socklen_t addrlen); + +/** + * Accept an incoming connection on a socket, returning a new socket for + * the connection, and storing the peer address in ADDR. + * + * \param fd The socket file descriptor. + * \param addr The structure to store the peer address in. + * \param addrlen The size of the data available in ADDR; upon return, the + * number of bytes stored in ADDR will be placed here. + * \return The new socket file descriptor, or -1 on error, and ERRNO set. + * + * Allowed ERRNO values: + * [EBADF] If FD is not a valid file descriptor. + * [ENOTSOCK] If FD in not a socket descriptor. + * [EOPNOTSUPP] If the socket is not a SOCK_STREAM socket. + * [EFAULT] If ADDR points outside the process's addressable space. + * [EWOULDBLOCK] If the socket is in non-blocking mode, and no connection + * attempt is currently ready. + * [EMFILE] If the process's descriptor table is full. + * [ENFILE] If the system's descriptor table is full. + */ +CPNIO_EXPORT int cpnio_accept (int fd, struct sockaddr *addr, socklen_t *addrlen); + +/** + * Send a datagram to the given address. + * + * \param fd The socket file descriptor. + * \param msg A pointer to the message to send. + * \param len The size of the message to send. + * \param flags Flags for sending. + * \param to The remote address to send the message to. + * \param tolen The size of the TO address structure. + * \return The number of bytes written, possibly zero, on success. Returns + * -1 on failure, and sets ERRNO. + * \see sendto(2) + * + * Allowed ERRNO values: + * [EBADF] + * [ENOTSOCK] + * [EFAULT] + * [EMSGSIZE] + * [EAGAIN] + * [ENOBUFS] + * [EACCES] + * [EHOSTUNREACH] + */ +CPNIO_EXPORT ssize_t cpnio_sendto (int fd, const void *msg, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen); + +/** + * Receive a message on a socket, storing the remote host's address in + * FROM. + * + * \param fd The socket file descriptor. + * \param buf The buffer to store received bytes in. + * \param flags Flags to control the receive. + * \param from Where to store the remote address. + * \param fromlen Pointer to the size of FROM; on return, it will contain the + * size of the structure placed in FROM. + * \return The number of bytes received on success. -1 on error, and ERRNO will + * be set. + * \see recvfrom(2) + * + * Allewed ERRNO values: + * [EBADF] FD is not a valid file descriptor. + * [ENOTCONN] If the socket is stream-oriented, and no prior call to + * connect(2) was made. + * [ENOTSOCK] FD is not a socket. + * [EAGAIN] FD is in non-blocking mode, and no message was + * immediately available. + * [EINTR] The system call was interrupted by a signal. + * [EFAULT] BUF, FROM, or FROMLEN lie outside the process's address + * space. + */ +CPNIO_EXPORT ssize_t cpnio_recvfrom (int fd, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen); + + +/** + * Control file descriptor properties. + * + * \param fd The file descriptor to control. + * \param cmd The command to execute. + * \param arg The command argument. + * \return A value other than -1, specific to CMD. On error, -1 is + * returned, and ERRNO is set. + * + * Allowed ERRNO values: + * FIXME + */ +CPNIO_EXPORT int cpnio_fcntl (int fd, int cmd, int arg); + + +/** + * Select from one of the given file descriptor sets a descriptor that + * is ready for the given operation (read, write, etc.). + * + * \param nfds A value one larger than the largest file + * descriptor. + * \param readfds A set of file descriptors to select for + * readability. + * \param writefds A set of file descriptors to select for + * writability. + * \param exceptfds A set of file descriptors to select for + * exceptional conditions. + * \param tm The selection timeout. + * \return The number of file descriptors selected, possibly zero, or + * -1 on error (and with ERRNO set). + */ +CPNIO_EXPORT int cpnio_select (int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *tm); + +/* + * We include the implementation file here, because our reference + * implementation is trivial, and the functions are declared extern + * inline. + * + * Implementations that need different implementations of these functions + * SHOULD remove this line, and compile javanio.c as a separate unit. + */ +#include "javanio.c" + +#endif /* __JAVANIO_H__ */ Index: native/jni/native-lib/cpnet.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/native-lib/cpnet.c,v retrieving revision 1.4 diff -u -r1.4 cpnet.c --- native/jni/native-lib/cpnet.c 8 Sep 2006 08:59:57 -0000 1.4 +++ native/jni/native-lib/cpnet.c 17 Sep 2006 06:17:15 -0000 @@ -598,8 +598,8 @@ struct hostent hret; struct hostent *result; jint buflen = 1024; - int herr; - int ret; + int herr = 0; + int ret = 0; int counter = 0; cpnet_address **addr_arr; int i; @@ -611,7 +611,13 @@ #ifdef HAVE_GETHOSTBYNAME_R ret = gethostbyname_r (hostname, &hret, buf, buflen, &result, &herr); #else - ret = gethostbyname (hostname); + hret.h_addr_list = NULL; + hret.h_addrtype = 0; + + result = gethostbyname (hostname); + if (result == NULL) + return -errno; + memcpy (&hret, result, sizeof (struct hostent)); #endif if (ret != 0 || result == NULL) { 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 17 Sep 2006 06:17:15 -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 17 Sep 2006 06:17:15 -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, int offset, int length) - throws IOException; - public long writeGathering(ByteBuffer[] srcs, int offset, int length) throws IOException { if (offset + length > srcs.length) throw new IndexOutOfBoundsException("offset + length > srcs.length"); - return writeGathering(fd, srcs, offset, length); + return writeGathering(nfd.getNativeFD(), srcs, offset, length); + } + + private native long writeGathering(int fd, ByteBuffer[] srcs, + int offset, int length) + throws IOException; + + /** + * Send a datagram to the given address. + * + * @param src The source buffer. + * @param dst The destination address. + * @return The number of bytes written. + * @throws IOException + */ + public int send(ByteBuffer src, InetSocketAddress dst) + throws IOException + { + InetAddress addr = dst.getAddress(); + if (addr == null) + throw new NullPointerException(); + if (addr instanceof Inet4Address) + return send(nfd.getNativeFD(), src, addr.getAddress(), dst.getPort()); + else if (addr instanceof Inet6Address) + return send6(nfd.getNativeFD(), src, addr.getAddress(), dst.getPort()); + else + throw new SocketException("unrecognized inet address type"); + } + + // Send to an IPv4 address. + private static native int send(int fd, ByteBuffer src, byte[] addr, int port) + throws IOException; + + // Send to an IPv6 address. + private static native int send6(int fd, ByteBuffer src, byte[] addr, int port) + throws IOException; + + /** + * Write a single byte. + * + * @param b The byte to write. + * @throws IOException + */ + public void write(int b) throws IOException + { + write(nfd.getNativeFD(), b); } + private static native void write(int fd, int b) throws IOException; + private native static void initIDs(); + // Network (socket) specific methods. + + /** + * Create a new socket. This method will initialize the native file + * descriptor state of this instance. + * + * @param stream Whether or not to create a streaming socket, or a datagram + * socket. + * @throws IOException If creating a new socket fails, or if this + * channel already has its native descriptor initialized. + */ + public void initSocket(boolean stream) throws IOException + { + if (nfd.isValid()) + throw new IOException("native FD already initialized"); + if (stream) + kind = Kind.SOCK_STREAM; + else + kind = Kind.SOCK_DGRAM; + nfd.setNativeFD(socket(stream)); + } + + /** + * Create a new socket, returning the native file descriptor. + * + * @param stream Set to true for streaming sockets; false for datagrams. + * @return The native file descriptor. + * @throws IOException If creating the socket fails. + */ + private static native int socket(boolean stream) throws IOException; + + /** + * Connect the underlying socket file descriptor to the remote host. + * + * @param saddr The address to connect to. + * @param timeout The connect timeout to use for blocking connects. + * @return True if the connection succeeded; false if the file descriptor + * is in non-blocking mode and the connection did not immediately + * succeed. + * @throws IOException If an error occurs while connecting. + */ + public boolean connect(InetSocketAddress saddr, int timeout) + throws IOException + { + InetAddress addr = saddr.getAddress(); + if (addr instanceof Inet4Address) + return connect(nfd.getNativeFD(), addr.getAddress(), saddr.getPort(), + timeout); + if (addr instanceof Inet6Address) + return connect6(nfd.getNativeFD(), addr.getAddress(), saddr.getPort(), + timeout); + throw new IOException("unsupported internet address"); + } + + private static native boolean connect(int fd, byte[] addr, int port, int timeout) + throws IOException; + + private static native boolean connect6(int fd, byte[] addr, int port, int timeout) + throws IOException; + + /** + * Disconnect this channel, if it is a datagram socket. Disconnecting + * a datagram channel will disassociate it from any address, so the + * socket will remain open, but can send and receive datagrams from + * any address. + * + * @throws IOException If disconnecting this channel fails, or if this + * channel is not a datagram channel. + */ + public void disconnect() throws IOException + { + if (kind != Kind.SOCK_DGRAM) + throw new IOException("can only disconnect datagram channels"); + disconnect(nfd.getNativeFD()); + } + + private static native void disconnect(int fd) throws IOException; + + public InetSocketAddress getLocalAddress() throws IOException + { + if (!nfd.isValid()) + return null; + ByteBuffer name = ByteBuffer.allocateDirect(18); + int namelen = getsockname(nfd.getNativeFD(), name); + if (namelen == 0) // not bound + return null; // XXX return some wildcard? + if (namelen == 4) + { + byte[] addr = new byte[4]; + name.get(addr); + int port = name.getShort() & 0xFFFF; + return new InetSocketAddress(Inet4Address.getByAddress(addr), port); + } + if (namelen == 16) + { + byte[] addr = new byte[16]; + name.get(addr); + int port = name.getShort() & 0xFFFF; + return new InetSocketAddress(Inet6Address.getByAddress(addr), port); + } + throw new SocketException("invalid address length"); + } + + private static native int getsockname(int fd, ByteBuffer name) + throws IOException; + + /** + * Returns the socket address of the remote peer this channel is connected + * to, or null if this channel is not yet connected. + * + * @return The peer address. + * @throws IOException + */ + public InetSocketAddress getPeerAddress() throws IOException + { + if (!nfd.isValid()) + return null; + ByteBuffer name = ByteBuffer.allocateDirect(18); + int namelen = getpeername (nfd.getNativeFD(), name); + if (namelen == 0) // not connected yet + return null; + if (namelen == 4) // IPv4 + { + byte[] addr = new byte[4]; + name.get(addr); + int port = name.getShort() & 0xFFFF; + return new InetSocketAddress(Inet4Address.getByAddress(addr), port); + } + else if (namelen == 16) // IPv6 + { + byte[] addr = new byte[16]; + name.get(addr); + int port = name.getShort() & 0xFFFF; + return new InetSocketAddress(Inet6Address.getByAddress(addr), port); + } + throw new SocketException("invalid address length"); + } + + /* + * The format here is the peer address, followed by the port number. + * The returned value is the length of the peer address; thus, there + * will be LEN + 2 valid bytes put into NAME. + */ + private static native int getpeername(int fd, ByteBuffer name) + throws IOException; + + /** + * Accept an incoming connection, returning a new VMChannel, or null + * if the channel is nonblocking and no connection is pending. + * + * @return The accepted connection, or null. + * @throws IOException If an IO error occurs. + */ + public VMChannel accept() throws IOException + { + int new_fd = accept(nfd.getNativeFD()); + if (new_fd == -1) // non-blocking accept had no pending connection + return null; + return new VMChannel(new_fd); + } + + private static native int accept(int native_fd) throws IOException; + + // File-specific methods. + + /** + * Open a file at PATH, initializing the native state to operate on + * that open file. + * + * @param path The absolute file path. + * @throws IOException If the file cannot be opened, or if this + * channel was previously initialized. + */ + public void openFile(String path, int mode) throws IOException + { + if (nfd.isValid() || nfd.isClosed()) + throw new IOException("can't reinitialize this channel"); + int fd = open(path, mode); + nfd.setNativeFD(fd); + kind = Kind.FILE; + } + + private static native int open(String path, int mode) throws IOException; + + public long position() throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + return position(nfd.getNativeFD()); + } + + private static native long position(int fd) throws IOException; + + public void seek(long pos) throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + seek(nfd.getNativeFD(), pos); + } + + private static native void seek(int fd, long pos) throws IOException; + + public void truncate(long length) throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + truncate(nfd.getNativeFD(), length); + } + + private static native void truncate(int fd, long len) throws IOException; + + public boolean lock(long pos, long len, boolean shared, boolean wait) + throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + return lock(nfd.getNativeFD(), pos, len, shared, wait); + } + + private static native boolean lock(int fd, long pos, long len, + boolean shared, boolean wait) + throws IOException; + + public void unlock(long pos, long len) throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + unlock(nfd.getNativeFD(), pos, len); + } + + private static native void unlock(int fd, long pos, long len) throws IOException; + + public long size() throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + return size(nfd.getNativeFD()); + } + + private static native long size(int fd) throws IOException; + + public MappedByteBuffer map(char mode, long position, int size) + throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + return map(nfd.getNativeFD(), mode, position, size); + } + + private static native MappedByteBuffer map(int fd, char mode, + long position, int size) + throws IOException; + + public boolean flush(boolean metadata) throws IOException + { + if (kind != Kind.FILE) + throw new IOException("not a file"); + return flush(nfd.getNativeFD(), metadata); + } + + private static native boolean flush(int fd, boolean metadata) throws IOException; + + // Close. + + /** + * Close this socket. The socket is also automatically closed when this + * object is finalized. + * + * @throws IOException If closing the socket fails, or if this object has + * no open socket. + */ + public void close() throws IOException + { + nfd.close(); + } + + static native void close(int native_fd) throws IOException; + + // Inner classes. + + /** + * A wrapper for a native file descriptor integer. This tracks the state + * of an open file descriptor, and ensures that + * + * This class need not be fully supported by virtual machines; if a + * virtual machine does not use integer file descriptors, or does and + * wishes to hide that, then the methods of this class may be stubbed out. + * + * System-specific classes that depend on access to native file descriptor + * integers SHOULD declare this fact. + */ + public final class State + { + private int native_fd; + private boolean valid; + private boolean closed; + + State() + { + native_fd = -1; + valid = false; + closed = false; + } + + public boolean isValid() + { + return valid; + } + + public boolean isClosed() + { + return closed; + } + + public int getNativeFD() throws IOException + { + if (!valid) + throw new IOException("invalid file descriptor"); + return native_fd; + } + + void setNativeFD(final int native_fd) throws IOException + { + if (valid) + throw new IOException("file descriptor already initialized"); + this.native_fd = native_fd; + valid = true; + } + + public void close() throws IOException + { + if (!valid) + throw new IOException("invalid file descriptor"); + try + { + VMChannel.close(native_fd); + } + finally + { + valid = false; + closed = true; + } + } + + public String toString() + { + if (!valid) + return "<>"; + if (closed) + return "<>"; + return String.valueOf(native_fd); + } + + protected void finalize() throws Throwable + { + try + { + if (valid) + close(); + } + finally + { + super.finalize(); + } + } + } + + /** + * An enumeration of possible kinds of channel. + */ + static class Kind // XXX enum + { + /** A streaming (TCP) socket. */ + static final Kind SOCK_STREAM = new Kind(); + + /** A datagram (UDP) socket. */ + static final Kind SOCK_DGRAM = new Kind(); + + /** A file. */ + static final Kind FILE = new Kind(); + + /** Something else; not a socket or file. */ + static final Kind OTHER = new Kind(); + + private Kind() { } + } } Index: vm/reference/gnu/java/nio/VMPipe.java =================================================================== RCS file: /cvsroot/classpath/classpath/vm/reference/gnu/java/nio/VMPipe.java,v retrieving revision 1.2 diff -u -r1.2 VMPipe.java --- vm/reference/gnu/java/nio/VMPipe.java 2 Jul 2005 20:33:08 -0000 1.2 +++ vm/reference/gnu/java/nio/VMPipe.java 17 Sep 2006 06:17:15 -0000 @@ -58,7 +58,24 @@ System.loadLibrary ("javanio"); } } - - static native void init(PipeImpl self, SelectorProvider provider) - throws IOException; + + /** + * Create a pipe, consisting of a readable VMChannel and a writable + * VMChannel. The readable channel is returned is the first element + * of the array, and the writable in the second. + * + * @return A pair of VMChannels; the first readable, the second + * writable. + * @throws IOException If the pipe cannot be created. + */ + static VMChannel[] pipe() throws IOException + { + VMChannel[] pipe = new VMChannel[2]; + int[] fds = pipe0(); + pipe[0] = new VMChannel(fds[0]); + pipe[1] = new VMChannel(fds[1]); + return pipe; + } + + private static native int[] pipe0() throws IOException; } Index: vm/reference/java/net/VMNetworkInterface.java =================================================================== RCS file: /cvsroot/classpath/classpath/vm/reference/java/net/VMNetworkInterface.java,v retrieving revision 1.4 diff -u -r1.4 VMNetworkInterface.java --- vm/reference/java/net/VMNetworkInterface.java 2 Mar 2006 00:36:44 -0000 1.4 +++ vm/reference/java/net/VMNetworkInterface.java 17 Sep 2006 06:17:15 -0000 @@ -40,6 +40,9 @@ import gnu.classpath.Configuration; +import java.nio.ByteBuffer; +import java.util.HashSet; +import java.util.Set; import java.util.Vector; /** @@ -54,22 +57,50 @@ */ final class VMNetworkInterface { + String name; + Set addresses; + + VMNetworkInterface(String name) + { + this.name = name; + addresses = new HashSet(); + } + static - { - if (Configuration.INIT_LOAD_LIBRARY) - System.loadLibrary("javanet"); - } + { + if (Configuration.INIT_LOAD_LIBRARY) + System.loadLibrary("javanet"); + + initIds(); + } + + private static native void initIds(); /** - * Returns a Vector of InetAddresses. The returned value will be - * 'condensed', meaning that all elements with the same interface - * name will be collapesed into one InetAddress for that name - * containing all addresses before the returning the result to the - * user. This means the native method can be implemented in a naive - * way mapping each address/interface to a name even if that means - * that the Vector contains multiple InetAddresses with the same - * interface name. + * Return a list of VM network interface objects. + * + * @return The list of network interfaces. + * @throws SocketException */ - public static native Vector getInterfaces() + public static native VMNetworkInterface[] getVMInterfaces() throws SocketException; + + private void addAddress(ByteBuffer addr) + throws SocketException, UnknownHostException + { + if (addr.remaining() == 4) + { + byte[] ipv4 = new byte[4]; + addr.get(ipv4); + addresses.add(Inet4Address.getByAddress(ipv4)); + } + else if (addr.remaining() == 16) + { + byte[] ipv6 = new byte[16]; + addr.get(ipv6); + addresses.add(Inet6Address.getByAddress(ipv6)); + } + else + throw new SocketException("invalid interface address"); + } } Index: vm/reference/java/nio/channels/VMChannels.java =================================================================== RCS file: /cvsroot/classpath/classpath/vm/reference/java/nio/channels/VMChannels.java,v retrieving revision 1.3 diff -u -r1.3 VMChannels.java --- vm/reference/java/nio/channels/VMChannels.java 2 Jul 2005 20:33:08 -0000 1.3 +++ vm/reference/java/nio/channels/VMChannels.java 17 Sep 2006 06:17:15 -0000 @@ -40,7 +40,7 @@ import gnu.java.nio.ChannelInputStream; import gnu.java.nio.ChannelOutputStream; -import gnu.java.nio.channels.FileChannelImpl; +import gnu.java.nio.FileChannelImpl; import java.io.FileInputStream; import java.io.FileOutputStream;