Hi,
this patch contains the bulk of my recent work on java.nio/java.net, the
respective VM classes and their native counterparts.

It consists of:
- adding multicast stuff
- fixing exception classes (IOException -> SocketException)
- removing the need for VMPlainDatagramSocketImpl and the removal of that class
- a missing case in getOptions (SO_REUSEADDR)
- a wrong constant in leave6
- a rework of accept along with a new method isThreadInterrupted()
- filtering of unwanted options for TCP in PlainSocketImpl
- using the user-given address of a remote host instead of the one provided by a
DNS lookup
- correctly handling SO_LINGER on the Java and the native side
- automatically closing of Socket whose connect() inside the constructor fails.
- documentation of the VM interface changes
- using 'Integer.valueOf()' instead of 'new Integer()'

I got positive feedback for the bigger changes and think that the minor fixes
are just ok.

ChangeLog:
2006-10-25  Robert Schuster  <[EMAIL PROTECTED]>

        * gnu/java/net/PlainDatagramSocketImpl.java:
        (connect): Use VMChannel instance for connect call.
        (getTimeToLive): Call VMPlainSocketImpl.getTimeToLive.
        (setTimeToLive): Call VMPlainSocketImpl.setTimeToLive.
        (setOption): Handle multicast options.
        (getOption): Handle multicast options.
        * gnu/java/net/PlainSocketImpl.java:
        (getTimeToLive): Call VMPlainSocketImpl.getTimeToLive.
        (setTimeToLive): Call VMPlainSocketImpl.setTimeToLive.
        (setOption): Filter unappropriate options.
        (getOption): Filter unappropriate options.
        (connect): Use given SocketAddress.
        (close): Reset address and port.
        (getInetAddress):
        * include/Makefile.am: Removed all occurences of
        gnu_java_net_VMPlainDatagramSocketImpl.h.
        * include/gnu_java_net_VMPlainDatagramSocketImpl.h: Removed.
        * native/jni/java-net/Makefile.am: Removed
        gnu_java_net_VMPlainDatagramSocketImpl.c from sources.
        * native/jni/java-net/gnu_java_net_VMPlainDatagramSocketImpl.c:
        Removed.
        as SocketException, declare to throw SocketException.
        * native/jni/java-nio/gnu_java_nio_VMChannel.c: Added definitions
        for SocketException and ConnectException.
        (Java_gnu_java_nio_VMChannel_connect): Throw SocketException instead
        of IOException.
        (Java_gnu_java_nio_VMChannel_connect6): Throw SocketException instead
        of IOException.
        (Java_gnu_java_nio_VMChannel_accept): Rewritten.
        (JCL_thread_interrupted): New function.
        (initIDs): Added initialisation for isThreadInterrupted method id.
        * native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c: Added
        CPNET_IP_TTL to java_sockopt enum.
        (Java_gnu_java_net_VMPlainSocketImpl_setOption): Handle CPNET_IP_TTL
        case, handle SO_LINGER case properly.
        (Java_gnu_java_net_VMPlainSocketImpl_getOption): Handle CPNET_IP_TTL
        case, handle SO_LINGER case properly.
        (Java_gnu_java_net_VMPlainSocketImpl_getMulticastInterface): New
        function.
        (Java_gnu_java_net_VMPlainSocketImpl_setMulticastInterface): New
        function.
        (Java_gnu_java_net_VMPlainSocketImpl_setMulticastInterface6): New
        function.
        (Java_gnu_java_net_VMPlainSocketImpl_leave6): Fixed constant to be
        IPV6_LEAVE_GROUP.
        * vm/reference/gnu/java/net/VMPlainDatagramSocketImpl.java: Removed.
        * vm/reference/gnu/java/nio/VMChannel.java:
        (connect(int, byte[], int, int)): Declare to throw SocketException.
        (connect6): Declare to throw SocketException.
        (connect(InetSocketAddress, int)): Catch IOException and rethrow
        (isThreadInterrupted): New method.
        * vm/reference/gnu/java/net/VMPlainSocketImpl.java: Added CP_IP_TTL
        field.
        (setTimeToLive): New method.
        (getTimeToLive): New method.
        (setMulticastInterface(int, InetAddress)): New method.
        (setMulticastInterface(int, int, Inet4Address): New method.
        (setMulticastInterface6(int, int, Inet6Address): New method.
        (setOptions): Handle SO_LINGER case.
        (getOptions): Add missing SO_REUSEADDR case.
        * java/net/Socket.java:
        (Socket(InetAddress, int, InetAddress, int, boolean)): Close socket
        when exception was thrown out of connect().
        (setSoLinger): Replaced instantiations with valueOf calls, replaced
        Boolean.FALSE with Integer.valueOf(-1).
        * native/jni/native-lib/cpio.h: Added cpio_closeOnExec declaration.
        * native/jni/native-lib/cpio.c: Added cpio_closeOnExec implementation.
        * NEWS: Documented VM interface changes.

That was a big one. :)

cya
Robert
Index: gnu/java/net/PlainSocketImpl.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/net/PlainSocketImpl.java,v
retrieving revision 1.14
diff -u -r1.14 PlainSocketImpl.java
--- gnu/java/net/PlainSocketImpl.java	17 Sep 2006 07:31:41 -0000	1.14
+++ gnu/java/net/PlainSocketImpl.java	25 Oct 2006 00:20:50 -0000
@@ -39,12 +39,9 @@
 
 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;
@@ -56,7 +53,6 @@
 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
@@ -148,26 +144,21 @@
   {
     switch (optionId)
       {
-        case IP_MULTICAST_IF:
-        case IP_MULTICAST_IF2:
-          throw new UnsupportedOperationException("FIXME");
-
+        case SO_LINGER:
         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);
+        default:
+          throw new SocketException("Unrecognized TCP option: " + optionId);
       }
   }
 
@@ -197,10 +188,26 @@
             throw se;
           }
       }
-    if (optionId == IP_MULTICAST_IF || optionId == IP_MULTICAST_IF2)
-      throw new UnsupportedOperationException ("can't get option " +
-                                               optionId + " yet");
-    return impl.getOption(optionId);
+    
+    // This filters options which are invalid for TCP.
+    switch (optionId)
+    {
+      case SO_LINGER:
+      case IP_MULTICAST_LOOP:
+      case SO_BROADCAST:
+      case SO_KEEPALIVE:
+      case SO_OOBINLINE:
+      case TCP_NODELAY:          
+      case IP_TOS:
+      case SO_RCVBUF:
+      case SO_SNDBUF:
+      case SO_TIMEOUT:
+      case SO_REUSEADDR:
+        return impl.getOption(optionId);
+      default:
+        throw new SocketException("Unrecognized TCP option: " + optionId);
+    }
+    
   }
 
   public void shutdownInput() throws IOException
@@ -274,7 +281,10 @@
     boolean connected = channel.connect(address, timeout);
     if (!connected)
       throw new SocketTimeoutException("connect timed out");
-    InetSocketAddress addr = channel.getVMChannel().getPeerAddress();
+    
+    // Using the given SocketAddress is important to preserve
+    // hostnames given by the caller.
+    InetSocketAddress addr = (InetSocketAddress) address; 
     this.address = addr.getAddress();
     this.port = addr.getPort();
   }
@@ -364,6 +374,9 @@
   {
     if (impl.getState().isValid())
       impl.close();
+    
+    address = null;
+    port = -1;
   }
 
   public void sendUrgentData(int data) throws IOException
@@ -417,11 +430,18 @@
   {
     if (channel == null)
       return null;
+    
     try
       {
         InetSocketAddress remote = channel.getVMChannel().getPeerAddress();
         if (remote == null)
           return null;
+        // To mimic behavior of the RI the InetAddress instance which was
+        // used to establish the connection is returned instead of one that
+        // was created by the native layer (this preserves exact hostnames).
+        if (address != null)
+          return address;
+        
         return remote.getAddress();
       }
     catch (IOException ioe)
@@ -471,6 +491,7 @@
   {
     if (channel == null)
       return -1;
+    
     try
       {
         InetSocketAddress remote = channel.getVMChannel().getPeerAddress();
Index: gnu/java/net/PlainDatagramSocketImpl.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/net/PlainDatagramSocketImpl.java,v
retrieving revision 1.13
diff -u -r1.13 PlainDatagramSocketImpl.java
--- gnu/java/net/PlainDatagramSocketImpl.java	22 Sep 2006 00:11:56 -0000	1.13
+++ gnu/java/net/PlainDatagramSocketImpl.java	25 Oct 2006 00:20:50 -0000
@@ -1,5 +1,5 @@
 /* PlainDatagramSocketImpl.java -- Default DatagramSocket implementation
-   Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005  Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -42,7 +42,6 @@
 
 import java.io.IOException;
 import java.io.InterruptedIOException;
-import java.lang.reflect.Field;
 import java.net.DatagramPacket;
 import java.net.DatagramSocketImpl;
 import java.net.InetAddress;
@@ -69,7 +68,6 @@
  */
 public final class PlainDatagramSocketImpl extends DatagramSocketImpl
 {
-  
   private final VMChannel channel;
   
   /**
@@ -171,7 +169,7 @@
    */
   protected void connect(InetAddress addr, int port) throws SocketException
   {
-    VMPlainDatagramSocketImpl.connect(this, addr, port);
+    channel.connect(new InetSocketAddress(addr, port), 0);
   }
 
   /**
@@ -203,7 +201,7 @@
    */
   protected synchronized void setTimeToLive(int ttl) throws IOException
   {
-    setOption(VMPlainDatagramSocketImpl.IP_TTL, new Integer(ttl));
+    impl.setTimeToLive(ttl);
   }
 
   /**
@@ -215,12 +213,7 @@
    */
   protected synchronized int getTimeToLive() throws IOException
   {
-    Object obj = getOption(VMPlainDatagramSocketImpl.IP_TTL);
-
-    if (! (obj instanceof Integer))
-      throw new IOException("Internal Error");
-
-    return ((Integer) obj).intValue();
+    return impl.getTimeToLive();
   }
 
   protected int getLocalPort()
@@ -318,30 +311,53 @@
   /**
    * Sets the value of an option on the socket
    *
-   * @param option_id The identifier of the option to set
-   * @param val The value of the option to set
+   * @param optionId The identifier of the option to set
+   * @param value The value of the option to set
    *
    * @exception SocketException If an error occurs
    */
-  public synchronized void setOption(int option_id, Object val)
+  public synchronized void setOption(int optionId, Object value)
     throws SocketException
   {
-    impl.setOption(option_id, val);
+    switch (optionId)
+      {
+        case IP_MULTICAST_IF:
+        case IP_MULTICAST_IF2:
+          impl.setMulticastInterface(optionId, (InetAddress) value);
+          break;
+
+        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);
+      }
   }
 
   /**
    * Retrieves the value of an option on the socket
    *
-   * @param option_id The identifier of the option to retrieve
+   * @param optionId The identifier of the option to retrieve
    *
    * @return The value of the option
    *
    * @exception SocketException If an error occurs
    */
-  public synchronized Object getOption(int option_id)
+  public synchronized Object getOption(int optionId)
     throws SocketException
   {
-    if (option_id == SO_BINDADDR)
+    if (optionId == SO_BINDADDR)
       {
         try
           {
@@ -361,7 +377,10 @@
             throw se;
           }
       }
-    return impl.getOption(option_id);
+    if (optionId == IP_MULTICAST_IF || optionId == IP_MULTICAST_IF2)
+      return impl.getMulticastInterface(optionId);
+
+    return impl.getOption(optionId);
   }
 
   /**
Index: include/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/include/Makefile.am,v
retrieving revision 1.71
diff -u -r1.71 Makefile.am
--- include/Makefile.am	20 Sep 2006 21:39:41 -0000	1.71
+++ include/Makefile.am	25 Oct 2006 00:20:50 -0000
@@ -125,7 +125,6 @@
 $(GTKPEER_H_FILES) \
 $(QTPEER_H_FILES) \
 $(GCONF_PREFS_FILES) \
-$(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_EpollSelectorImpl.h \
@@ -180,8 +179,6 @@
 $(top_srcdir)/include/gnu_java_util_prefs_gconf_%.h: $(top_builddir)/$(CLASSDIR)/gnu/java/util/prefs/gconf/%.class
 	$(JAVAH) -o $@ gnu.java.util.prefs.gconf.$*
 
-$(top_srcdir)/include/gnu_java_net_VMPlainDatagramSocketImpl.h: $(top_srcdir)/vm/reference/gnu/java/net/VMPlainDatagramSocketImpl.java
-	$(JAVAH) -o $@ gnu.java.net.VMPlainDatagramSocketImpl
 $(top_srcdir)/include/gnu_java_net_VMPlainSocketImpl.h: $(top_srcdir)/vm/reference/gnu/java/net/VMPlainSocketImpl.java
 	$(JAVAH) -o $@ gnu.java.net.VMPlainSocketImpl
 $(top_srcdir)/include/gnu_java_net_local_LocalSocketImpl.h: $(top_srcdir)/gnu/java/net/local/LocalSocketImpl.java
Index: native/jni/java-net/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/java-net/Makefile.am,v
retrieving revision 1.18
diff -u -r1.18 Makefile.am
--- native/jni/java-net/Makefile.am	21 Aug 2006 23:34:45 -0000	1.18
+++ native/jni/java-net/Makefile.am	25 Oct 2006 00:20:50 -0000
@@ -13,7 +13,6 @@
 			java_net_VMInetAddress.c \
 			java_net_VMNetworkInterface.c \
 			java_net_VMURLConnection.c \
-			gnu_java_net_VMPlainDatagramSocketImpl.c \
                         gnu_java_net_VMPlainSocketImpl.c \
 			$(local_sources)
 
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.12
diff -u -r1.12 gnu_java_net_VMPlainSocketImpl.c
--- native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c	22 Oct 2006 16:28:19 -0000	1.12
+++ native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c	25 Oct 2006 00:20:50 -0000
@@ -49,6 +49,7 @@
 #include <ifaddrs.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
+#include <net/if.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -58,16 +59,14 @@
 #include <jni.h>
 #include <jcl.h>
 
-/* #include "javanet.h" */
+#include "cpnative.h"
+#include "cpnet.h"
+#include "cpio.h"
+#include "javanet.h"
 
 #include "gnu_java_net_VMPlainSocketImpl.h"
 
-#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") 
-
+#define THROW_NO_NETWORK(env) JCL_ThrowException (env, "java/lang/InternalError", "this platform not configured for network support")
 
 /*
  * Class:     gnu_java_net_VMPlainSocketImpl
@@ -104,6 +103,8 @@
 
   if (-1 == ret)
     JCL_ThrowException (env, BIND_EXCEPTION, strerror (errno));
+    
+  cpio_closeOnExec(ret);
 }
 
 
@@ -160,7 +161,10 @@
 }
 
 
-/* These constants are also defined in java/net/SocketOptions.java */
+/* These constants are also defined in java/net/SocketOptions.java.
+ * Except for CPNET_IP_TTL which is defined in 
+ * vm/reference/gnu/java/net/VMPlainSocketImpl.java .
+ */
 enum java_sockopt {
   CPNET_SO_KEEPALIVE = 0x8,
   CPNET_SO_LINGER = 0x80,
@@ -175,7 +179,8 @@
   CPNET_IP_MULTICAST_IF = 0x10,
   CPNET_IP_MULTICAST_IF2 = 0x1F,
   CPNET_IP_MULTICAST_LOOP = 0x12,
-  CPNET_IP_TOS = 0x03
+  CPNET_IP_TOS = 0x03,
+  CPNET_IP_TTL = 0x1E61
 };
 
 
@@ -197,7 +202,7 @@
   struct timeval _timeo;
   void *optval = (void *) &_value;
   socklen_t optlen = sizeof (int);
-
+  
   switch (joption)
     {
     case CPNET_IP_MULTICAST_LOOP:
@@ -211,7 +216,7 @@
 
     case CPNET_SO_LINGER:
       optname = SO_LINGER;
-      if (_value == 0)
+      if (_value == -1)
         _linger.l_onoff = 0;
       else
         _linger.l_onoff = 1;
@@ -258,6 +263,11 @@
       optname = IP_TOS;
       break;
 
+    case CPNET_IP_TTL:
+      level = IPPROTO_IP;
+      optname = IP_TTL;
+      break;
+
     case CPNET_SO_BINDADDR:
     case CPNET_IP_MULTICAST_IF:
     case CPNET_IP_MULTICAST_IF2:
@@ -341,6 +351,11 @@
       optname = IP_TOS;
       break;
 
+    case CPNET_IP_TTL:
+      level = IPPROTO_IP;
+      optname = IP_TTL;
+      break;
+
     case CPNET_SO_BINDADDR:
     case CPNET_IP_MULTICAST_IF:
     case CPNET_IP_MULTICAST_IF2:
@@ -351,14 +366,108 @@
   if (getsockopt (fd, level, optname, optval, &optlen) == -1)
     JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 
+  /* Returns the linger value if it is enabled or -1 in case
+   * it is disabled. This is how the Java API expects it.
+   */
   if (joption == CPNET_SO_LINGER)
-    return linger.l_linger;
+    return (linger.l_onoff) ? linger.l_linger : -1;
   if (joption == CPNET_SO_TIMEOUT)
     return (timeo.tv_sec * 1000) + (timeo.tv_usec / 1000);
 
   return value;
 }
 
+JNIEXPORT void JNICALL
+Java_gnu_java_net_VMPlainSocketImpl_setMulticastInterface (JNIEnv *env,
+                                                           jclass c __attribute__((unused)),
+                                                           jint fd,
+                                                           jint optionId __attribute__((unused)),
+                                                           jobject addr)
+{
+  int result;
+  cpnet_address *cpaddr = _javanet_get_ip_netaddr (env, addr);
+
+  if ((*env)->ExceptionOccurred (env))
+    return;
+
+  result = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
+                      (struct sockaddr *) cpaddr->data, cpaddr->len);
+
+  cpnet_freeAddress (env, cpaddr);
+  
+  if (result == -1)
+    JCL_ThrowException (env, SOCKET_EXCEPTION, cpnative_getErrorString (errno));
+}
+
+JNIEXPORT void JNICALL
+Java_gnu_java_net_VMPlainSocketImpl_setMulticastInterface6 (JNIEnv *env,
+                                                           jclass c __attribute__((unused)),
+                                                           jint fd,
+                                                           jint optionId __attribute__((unused)),
+                                                           jstring ifname)
+{
+#ifdef HAVE_SETSOCKOPT
+#ifdef HAVE_INET6	
+  int result;
+  const char *str_ifname = JCL_jstring_to_cstring (env, ifname);
+  u_int if_index;
+
+  if ((*env)->ExceptionOccurred (env))
+    {
+      JCL_free_cstring(env, ifname, str_ifname);
+      return;
+    }
+
+  if_index = if_nametoindex(str_ifname);
+  if (!if_index)
+    {
+      JCL_free_cstring(env, ifname, str_ifname);
+      JCL_ThrowException (env, SOCKET_EXCEPTION, "interface does not exist");
+      return;
+    }
+
+  result = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+                      (u_int *) &if_index, sizeof(if_index));
+
+  JCL_free_cstring(env, ifname, str_ifname);
+  
+  if (result == -1)
+    JCL_ThrowException (env, SOCKET_EXCEPTION, cpnative_getErrorString (errno));
+#else
+  (void) fd;
+  JCL_ThrowException (env, "java/lang/InternalError",
+                      "IPv6 support not available");
+#endif /* HAVE_INET6 */
+#else
+  (void) fd;
+  JCL_ThrowException (env, "java/lang/InternalError",
+                      "socket options not supported");
+#endif /* HAVE_SETSOCKOPT */
+}
+
+JNIEXPORT jobject JNICALL
+Java_gnu_java_net_VMPlainSocketImpl_getMulticastInterface (JNIEnv *env,
+                                                           jclass c __attribute__((unused)),
+                                                           jint fd,
+                                                           jint optionId __attribute__((unused)))
+{
+  jobject obj;
+  cpnet_address *cpaddr;
+  int result = cpnet_getMulticastIF (env, fd, &cpaddr);
+ 
+  if (result != CPNATIVE_OK)
+    {
+      JCL_ThrowException (env, SOCKET_EXCEPTION,
+                          cpnative_getErrorString (result));
+      return (0);
+    }
+
+  obj = _javanet_create_inetaddress (env, cpaddr);
+  cpnet_freeAddress (env, cpaddr);
+
+  return obj;
+}
+
 
 /*
  * Class:     gnu_java_net_VMPlainSocketImpl
@@ -540,7 +649,7 @@
 
   (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
 
-  if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+  if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
                         &maddr, sizeof (struct ipv6_mreq)))
     JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 #else
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.6
diff -u -r1.6 gnu_java_nio_VMChannel.c
--- native/jni/java-nio/gnu_java_nio_VMChannel.c	22 Oct 2006 16:28:19 -0000	1.6
+++ native/jni/java-nio/gnu_java_nio_VMChannel.c	25 Oct 2006 00:20:50 -0000
@@ -59,6 +59,7 @@
 #include <jni.h>
 #include <jcl.h>
 
+#include "cpio.h"
 #include "gnu_java_nio_VMChannel.h"
 #include "javanio.h"
 
@@ -66,7 +67,9 @@
 #include <fcntl.h>
 #endif /* HAVE_FCNTL_H */
 
+#define CONNECT_EXCEPTION "java/net/ConnectException"
 #define IO_EXCEPTION "java/io/IOException"
+#define SOCKET_EXCEPTION "java/net/SocketException"
 #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"
@@ -103,6 +106,7 @@
 int JCL_init_buffer(JNIEnv *, struct JCL_buffer *, jobject);
 void JCL_release_buffer(JNIEnv *, struct JCL_buffer *, jobject, jint);
 void JCL_cleanup_buffers(JNIEnv *, struct JCL_buffer *, jint, jobjectArray, jint, jlong);
+int JCL_thread_interrupted(JNIEnv *, jclass);
 
 static jfieldID address_fid;
 static jmethodID get_position_mid;
@@ -112,6 +116,7 @@
 static jmethodID has_array_mid;
 static jmethodID array_mid;
 static jmethodID array_offset_mid;
+static jmethodID thread_interrupted_mid;
 
 jmethodID
 get_method_id(JNIEnv *env,  jclass clazz, const char *name, 
@@ -121,7 +126,7 @@
 /*   NIODBG("name: %s; sig: %s", name, sig); */
   if (mid == NULL)
     {
-  	  JCL_ThrowException(env, "java/lang/InternalError", name);
+      JCL_ThrowException(env, "java/lang/InternalError", name);
       return NULL;
     }
   
@@ -249,6 +254,13 @@
 }
 
 
+int
+JCL_thread_interrupted(JNIEnv *env, jclass c)
+{
+  return (int) (*env)->CallBooleanMethod(env, c, thread_interrupted_mid);
+}
+
+
 /*
  * Class:     gnu_java_nio_VMChannel
  * Method:    stdin_fd
@@ -293,7 +305,7 @@
 
 JNIEXPORT void JNICALL 
 Java_gnu_java_nio_VMChannel_initIDs  (JNIEnv *env, 
-	jclass clazz __attribute__ ((__unused__)))
+	jclass clazz)
 {
   jclass bufferClass = JCL_FindClass(env, "java/nio/Buffer");
   jclass byteBufferClass = JCL_FindClass(env, "java/nio/ByteBuffer");
@@ -318,6 +330,8 @@
   has_array_mid = get_method_id(env, byteBufferClass, "hasArray", "()Z");
   array_mid = get_method_id(env, byteBufferClass, "array", "()[B");
   array_offset_mid = get_method_id(env, byteBufferClass, "arrayOffset", "()I");
+  
+  thread_interrupted_mid = get_method_id(env, clazz, "isThreadInterrupted", "()Z");
 }
 
 JNIEXPORT void JNICALL 
@@ -975,7 +989,8 @@
 
   if ((*env)->GetArrayLength (env, addr) != 4)
     {
-      JCL_ThrowException (env, "java/io/IOException", "expecting 4-byte address");
+      JCL_ThrowException (env, SOCKET_EXCEPTION,
+                          "expecting 4-byte address");
       return JNI_FALSE;
     }
 
@@ -986,7 +1001,7 @@
       origflags = fcntl (fd, F_GETFL, 0);
       if (origflags == -1)
         {
-          JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
           return JNI_FALSE;
         }
       /* Set nonblocking mode, if not already set. */
@@ -995,7 +1010,7 @@
           flags = origflags | O_NONBLOCK;
           if (fcntl (fd, F_SETFL, flags) == -1)
             {
-              JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
               return JNI_FALSE;
             }
         }
@@ -1024,7 +1039,7 @@
           if (fcntl (fd, F_SETFL, origflags) == -1)
             {
               /* oops */
-              JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
               return JNI_FALSE;
             }
         }
@@ -1035,7 +1050,7 @@
           ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
           if (ret == -1)
             {
-              JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
               return JNI_FALSE;
             }
           if (ret == 0) /* connect timed out */
@@ -1048,13 +1063,13 @@
         }
       else if (ECONNREFUSED == errno)
         {
-          JCL_ThrowException (env, "java/net/ConnectException",
+          JCL_ThrowException (env, CONNECT_EXCEPTION,
                               strerror (errno));
           return JNI_FALSE;
         }
       else
         {
-          JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
           return JNI_FALSE;
         }
     }
@@ -1065,13 +1080,13 @@
         return JNI_FALSE;
       else if (ECONNREFUSED == errno)
         {
-          JCL_ThrowException (env, "java/net/ConnectException",
+          JCL_ThrowException (env, CONNECT_EXCEPTION,
                               strerror (errno));
           return JNI_FALSE;
         }
       else
         {
-          JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
           return JNI_FALSE;
         }
     }
@@ -1082,7 +1097,7 @@
   (void) addr;
   (void) port;
   (void) timeout;
-  JCL_ThrowException (env, IO_EXCEPTION, "connect not supported");
+  JCL_ThrowException (env, SOCKET_EXCEPTION, "connect not supported");
   return JNI_FALSE;
 #endif /* HAVE_CONNECT */
 }
@@ -1111,7 +1126,7 @@
       origflags = fcntl (fd, F_GETFL, 0);
       if (origflags == -1)
         {
-          JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
           return JNI_FALSE;
         }
       /* Set nonblocking mode, if not already set. */
@@ -1120,7 +1135,7 @@
           flags = origflags | O_NONBLOCK;
           if (fcntl (fd, F_SETFL, flags) == -1)
             {
-              JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
               return JNI_FALSE;
             }
         }
@@ -1148,7 +1163,7 @@
           if (fcntl (fd, F_SETFL, origflags) == -1)
             {
               /* oops */
-              JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
               return JNI_FALSE;
             }
         }
@@ -1159,7 +1174,7 @@
           ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
           if (ret == -1)
             {
-              JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
               return JNI_FALSE;
             }
           if (ret == 0) /* connect timed out */
@@ -1172,13 +1187,13 @@
         }
       else if (ECONNREFUSED == errno)
         {
-          JCL_ThrowException (env, "java/net/ConnectException",
+          JCL_ThrowException (env, CONNECT_EXCEPTION,
                               strerror (errno));
           return JNI_FALSE;
         }
       else
         {
-          JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
+          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
           return JNI_FALSE;
         }
     }
@@ -1189,13 +1204,13 @@
         return JNI_FALSE;
       else if (ECONNREFUSED == errno)
         {
-          JCL_ThrowException (env, "java/net/ConnectException",
+          JCL_ThrowException (env, CONNECT_EXCEPTION,
                               strerror (errno));
           return JNI_FALSE;
         }
       else
         {
-          JCL_ThrowException (env, "java/io/IOException", strerror (errno));
+          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
           return JNI_FALSE;
         }
     }
@@ -1206,7 +1221,7 @@
   (void) addr;
   (void) port;
   (void) timeout;
-  JCL_ThrowException (env, IO_EXCEPTION, "IPv6 connect not supported");
+  JCL_ThrowException (env, SOCKET_EXCEPTION, "IPv6 connect not supported");
   return JNI_FALSE;
 #endif /* HAVE_CONNECT && HAVE_INET6 */
 }
@@ -1340,11 +1355,12 @@
  */
 JNIEXPORT jint JNICALL
 Java_gnu_java_nio_VMChannel_accept (JNIEnv *env,
-                                    jclass clazz __attribute__((unused)),
+                                    jclass clazz,
                                     jint fd)
 {
 #ifdef HAVE_ACCEPT
   int ret;
+  int tmp_errno = 0;
 
 #ifdef HAVE_INET6
   struct sockaddr_in6 addr;
@@ -1357,14 +1373,38 @@
   do
     {
       ret = cpnio_accept (fd, (struct sockaddr *) &addr, &alen);
+      tmp_errno = errno;
+      
+      if (ret == -1)
+        switch (tmp_errno)
+        {
+          case EINTR:
+            /* Check if interrupted by Thread.interrupt(). If not then some
+             * other unrelated signal interrupted the system function and
+             * we should start over again.
+             */
+            if (JCL_thread_interrupted(env, clazz))
+              {
+                JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
+                return -1;
+              }
+            break;
+#if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN
+          case EWOULDBLOCK:
+#endif
+          case EAGAIN:
+            /* Socket in non-blocking mode and no pending connection. */
+            return -1;
+          default:
+            JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
+            return -1;
+        }
+      else
+        break;
     }
-  while (ret == -1 && EINTR == errno);
+  while (1);
 
-  if (ret == -1)
-    {
-      if (EWOULDBLOCK != ret && EAGAIN != ret)
-        JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
-    }
+  cpio_closeOnExec(ret);
 
   return ret;
 #else
Index: native/jni/native-lib/cpio.c
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/native-lib/cpio.c,v
retrieving revision 1.5
diff -u -r1.5 cpio.c
--- native/jni/native-lib/cpio.c	23 Sep 2006 05:17:46 -0000	1.5
+++ native/jni/native-lib/cpio.c	25 Oct 2006 00:20:50 -0000
@@ -473,3 +473,13 @@
   strncpy (filename, dBuf->d_name, FILENAME_MAX);
   return 0;
 }
+
+
+int
+cpio_closeOnExec(int fd)
+{
+	if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1)
+	  return errno;
+	  
+	return 0;
+}
Index: native/jni/native-lib/cpio.h
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/native-lib/cpio.h,v
retrieving revision 1.4
diff -u -r1.4 cpio.h
--- native/jni/native-lib/cpio.h	23 Sep 2006 05:17:46 -0000	1.4
+++ native/jni/native-lib/cpio.h	25 Oct 2006 00:20:50 -0000
@@ -64,6 +64,7 @@
 JNIEXPORT int cpio_write (int fd, const void *data, jint len, jint *bytes_written);
 JNIEXPORT int cpio_fsync (int fd);
 JNIEXPORT int cpio_truncate (int fd, jlong size);
+JNIEXPORT int cpio_closeOnExec(int fd);
 
 #define CPFILE_FILE 0
 #define CPFILE_DIRECTORY 1
Index: vm/reference/gnu/java/nio/VMChannel.java
===================================================================
RCS file: /cvsroot/classpath/classpath/vm/reference/gnu/java/nio/VMChannel.java,v
retrieving revision 1.4
diff -u -r1.4 VMChannel.java
--- vm/reference/gnu/java/nio/VMChannel.java	27 Sep 2006 21:30:44 -0000	1.4
+++ vm/reference/gnu/java/nio/VMChannel.java	25 Oct 2006 00:20:51 -0000
@@ -39,7 +39,6 @@
 package gnu.java.nio;
 
 import gnu.classpath.Configuration;
-import gnu.classpath.jdwp.exception.NotImplementedException;
 
 import java.io.IOException;
 import java.net.Inet4Address;
@@ -379,23 +378,37 @@
    * @throws IOException If an error occurs while connecting.
    */
   public boolean connect(InetSocketAddress saddr, int timeout)
-    throws IOException
+    throws SocketException
   {
+    int fd;
+
     InetAddress addr = saddr.getAddress();
+ 
+    // Translates an IOException into a SocketException to conform
+    // to the throws clause.
+    try
+      {
+        fd = nfd.getNativeFD();
+      }
+    catch (IOException ioe)
+      {
+        throw new SocketException(ioe.getMessage());
+      }
+
     if (addr instanceof Inet4Address)
-      return connect(nfd.getNativeFD(), addr.getAddress(), saddr.getPort(),
+      return connect(fd, addr.getAddress(), saddr.getPort(),
                      timeout);
     if (addr instanceof Inet6Address)
-      return connect6(nfd.getNativeFD(), addr.getAddress(), saddr.getPort(),
+      return connect6(fd, addr.getAddress(), saddr.getPort(),
                       timeout);
-    throw new IOException("unsupported internet address");
+    throw new SocketException("unsupported internet address");
   }
   
   private static native boolean connect(int fd, byte[] addr, int port, int timeout)
-    throws IOException;
+    throws SocketException;
   
   private static native boolean connect6(int fd, byte[] addr, int port, int timeout)
-    throws IOException;
+    throws SocketException;
   
   /**
    * Disconnect this channel, if it is a datagram socket. Disconnecting
@@ -614,6 +627,17 @@
   }
   
   static native void close(int native_fd) throws IOException;
+  
+  /**
+   * <p>Provides a simple mean for the JNI code to find out whether the
+   * current thread was interrupted by a call to Thread.interrupt().</p>
+   * 
+   * @return
+   */
+  final boolean isThreadInterrupted()
+  {
+    return Thread.currentThread().isInterrupted();
+  }
 
   // Inner classes.
   
Index: vm/reference/gnu/java/net/VMPlainSocketImpl.java
===================================================================
RCS file: /cvsroot/classpath/classpath/vm/reference/gnu/java/net/VMPlainSocketImpl.java,v
retrieving revision 1.4
diff -u -r1.4 VMPlainSocketImpl.java
--- vm/reference/gnu/java/net/VMPlainSocketImpl.java	17 Sep 2006 07:31:43 -0000	1.4
+++ vm/reference/gnu/java/net/VMPlainSocketImpl.java	25 Oct 2006 00:20:51 -0000
@@ -43,15 +43,11 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.NetworkInterface;
-import java.net.SocketAddress;
 import java.net.SocketException;
-import java.net.SocketImpl;
 import java.net.SocketOptions;
-import java.net.UnknownHostException;
 
 import gnu.classpath.Configuration;
 import gnu.java.nio.VMChannel;
-import gnu.java.nio.VMChannel.State;
 
 /**
  * The VM interface for [EMAIL PROTECTED] gnu.java.net.PlainSocketImpl}.
@@ -61,6 +57,10 @@
  */
 public final class VMPlainSocketImpl
 {
+  /** Option id for time to live
+   */
+  private static final int CP_IP_TTL = 0x1E61;
+
   private final State nfd;
   
   /**
@@ -91,6 +91,41 @@
     return nfd;
   }
 
+  /** This method exists to hide the CP_IP_TTL value from
+   * higher levels.
+   *
+   * Always think of JNode ... :)
+   */
+  public void setTimeToLive(int ttl)
+    throws SocketException
+  {
+    try
+      {
+        setOption(nfd.getNativeFD(), CP_IP_TTL, ttl);
+      }
+    catch (IOException ioe)
+      {
+        SocketException se = new SocketException();
+        se.initCause(ioe);
+        throw se;
+      }
+  }
+
+  public int getTimeToLive()
+    throws SocketException
+  {
+    try
+      {
+        return getOption(nfd.getNativeFD(), CP_IP_TTL);
+      }
+    catch (IOException ioe)
+      {
+        SocketException se = new SocketException();
+        se.initCause(ioe);
+        throw se;
+      }
+  }
+
   public void setOption(int optionId, Object optionValue)
     throws SocketException
   {
@@ -98,7 +133,14 @@
     if (optionValue instanceof Integer)
       value = ((Integer) optionValue).intValue();
     else if (optionValue instanceof Boolean)
-      value = ((Boolean) optionValue).booleanValue() ? 1 : 0;
+      // Switching off the linger behavior is done by setting
+      // the value to -1. This is how the Java API interprets
+      // it.
+      value = ((Boolean) optionValue).booleanValue()
+              ? 1
+              : (optionId == SocketOptions.SO_LINGER)
+              ? -1
+              : 0;
     else
       throw new IllegalArgumentException("option value type "
                                          + optionValue.getClass().getName());
@@ -118,6 +160,41 @@
   private static native void setOption(int fd, int id, int value)
     throws SocketException;
 
+  public void setMulticastInterface(int optionId, InetAddress addr)
+    throws SocketException
+  {
+    try
+      {
+        if (addr instanceof Inet4Address)
+          setMulticastInterface(nfd.getNativeFD(), optionId, (Inet4Address) addr);
+        else if (addr instanceof Inet6Address)
+          {
+            NetworkInterface iface = NetworkInterface.getByInetAddress(addr);
+            setMulticastInterface6(nfd.getNativeFD(), optionId, iface.getName());
+          }
+        else
+          throw new SocketException("Unknown address format: " + addr);
+      }
+    catch (SocketException se)
+      {
+        throw se;
+      }
+    catch (IOException ioe)
+      {
+        SocketException se = new SocketException();
+        se.initCause(ioe);
+        throw se;
+      }
+  }
+
+  private static native void setMulticastInterface(int fd,
+                                                   int optionId,
+                                                   Inet4Address addr);
+
+  private static native void setMulticastInterface6(int fd,
+                                                    int optionId,
+                                                    String ifName);
+
   /**
    * Get a socket option. This implementation is only required to support
    * socket options that are boolean values, which include:
@@ -126,6 +203,7 @@
    *  SocketOptions.SO_BROADCAST
    *  SocketOptions.SO_KEEPALIVE
    *  SocketOptions.SO_OOBINLINE
+   *  SocketOptions.SO_REUSEADDR
    *  SocketOptions.TCP_NODELAY
    * 
    * and socket options that are integer values, which include:
@@ -161,6 +239,7 @@
         case SocketOptions.SO_BROADCAST:
         case SocketOptions.SO_KEEPALIVE:
         case SocketOptions.SO_OOBINLINE:
+        case SocketOptions.SO_REUSEADDR:
         case SocketOptions.TCP_NODELAY:
           return Boolean.valueOf(value != 0);
           
@@ -178,6 +257,33 @@
   }
   
   private static native int getOption(int fd, int id) throws SocketException;
+
+  /**
+   * Returns an Inet4Address or Inet6Address instance belonging to the
+   * interface which is set as the multicast interface.
+   *
+   * The optionId is provided to make it possible that the native
+   * implementation may do something different depending on whether
+   * the value is SocketOptions.IP_MULTICAST_IF or 
+   * SocketOptions.IP_MULTICAST_IF2.
+   */
+  public InetAddress getMulticastInterface(int optionId)
+    throws SocketException
+  {
+    try
+      {
+        return getMulticastInterface(nfd.getNativeFD(), optionId);
+      }
+    catch (IOException ioe)
+      {
+        SocketException se = new SocketException();
+        se.initCause(ioe);
+        throw se;
+      }
+  }
+
+  private static native InetAddress getMulticastInterface(int fd,
+                                                          int optionId);
   
   /**
    * Binds this socket to the given local address and port.
@@ -402,4 +508,5 @@
         }
     }
   }
-}
\ No newline at end of file
+}
+
Index: java/net/Socket.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/net/Socket.java,v
retrieving revision 1.59
diff -u -r1.59 Socket.java
--- java/net/Socket.java	5 Oct 2006 14:50:04 -0000	1.59
+++ java/net/Socket.java	25 Oct 2006 00:20:51 -0000
@@ -298,8 +298,26 @@
       laddr == null ? null : new InetSocketAddress(laddr, lport);
     bind(bindaddr);
 
-    // connect socket
-    connect(new InetSocketAddress(raddr, rport));
+    // Connect socket in case of Exceptions we must close the socket
+    // because an exception in the constructor means that the caller will
+    // not have a reference to this instance.
+    // Note: You may have the idea that the exception treatment
+    // should be moved into connect() but there is a Mauve test which
+    // shows that a failed connect should not close the socket.
+    try
+      {
+        connect(new InetSocketAddress(raddr, rport));
+      }
+    catch (IOException ioe)
+      {
+        impl.close();
+        throw ioe;
+      }
+    catch (RuntimeException re)
+      {
+        impl.close();
+        throw re;
+      }
 
     // FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port,
     // i.e. '0' and if localAddr is unspecified, use getLocalAddress() as
@@ -692,10 +710,10 @@
 	if (linger > 65535)
 	  linger = 65535;
 
-	getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger));
+	getImpl().setOption(SocketOptions.SO_LINGER, Integer.valueOf(linger));
       }
     else
-      getImpl().setOption(SocketOptions.SO_LINGER, Boolean.valueOf(false));
+      getImpl().setOption(SocketOptions.SO_LINGER, Integer.valueOf(-1));
   }
 
   /**
@@ -1190,7 +1208,7 @@
   {
     if (impl == null)
       return false;
-
+    
     return impl.getInetAddress() != null;
   }
 
@@ -1223,6 +1241,7 @@
   public boolean isClosed()
   {
     SocketChannel channel = getChannel();
+    
     return impl == null || (channel != null && ! channel.isOpen());
   }
 
Index: NEWS
===================================================================
RCS file: /cvsroot/classpath/classpath/NEWS,v
retrieving revision 1.169
diff -u -r1.169 NEWS
--- NEWS	20 Sep 2006 22:35:55 -0000	1.169
+++ NEWS	25 Oct 2006 00:20:53 -0000
@@ -39,11 +39,13 @@
 * gnu.java.nio.VMPipe has been similarly changed.
 * gnu.java.net.VMPlainSocketImpl has been changed to remove some
   functionality now provided by VMChannel; datagram socket-specific
-  methods have also been moved here, deprecating
-  VMPlainDatagramSocketImpl.
+  methods have also been moved here, deprecating VMPlainDatagramSocketImpl.
+* gnu.java.net.VMPlainDatagramSocketImpl removed.
 
 New in release 0.92 (Aug 9, 2006)
 
+* GConf is used as a backend for java.util.prefs. GNU Classpath 
+  thanks to Mario Torre for this contribution!
 * libjawtgnu.so has been renamed libjawt.so for binary compatibility.
   libjawt.so should be installed in a VM-specific directory rather
   than directly in /usr/lib.  Proprietary VMs put their libjawt.so

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to