Hi.

A few of us were chatting in IRC today about local socket support, aka Unix domain sockets, in Classpath (that is, where you bind a socket to a special file, instead of to a network address. This is used mostly for IPC; for example, local X11 connections can use local sockets). I mentioned that I had written such a thing, and some people were interested in seeing this in Classpath.

So, do we want this? The attached patch is my implementation of this, which basically introduces three new classes:

  gnu.java.net.local.LocalServerSocket
  gnu.java.net.local.LocalSocket
  gnu.java.net.local.LocalSocketAddress

Which operate similarly to how normal Sockets do, but over local sockets.

Note that this patch has to be cleaned up a lot, mostly to add detection for local socket support in configure. Also, SocketChannel support is missing, but may not be too hard to implement.

If there is interest, I can polish this up some more and check it in.

Thanks.

--- /dev/null   2006-04-12 17:45:39.000000000 -0700
+++ include/gnu_java_net_local_LocalSocketImpl.h        2006-04-12 
16:41:25.000000000 -0700
@@ -0,0 +1,31 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+
+#ifndef __gnu_java_net_local_LocalSocketImpl__
+#define __gnu_java_net_local_LocalSocketImpl__
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_create (JNIEnv 
*env, jobject, jboolean);
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_listen (JNIEnv 
*env, jobject, jint);
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_accept (JNIEnv 
*env, jobject, jobject);
+JNIEXPORT jint JNICALL Java_gnu_java_net_local_LocalSocketImpl_available 
(JNIEnv *env, jobject);
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_close (JNIEnv 
*env, jobject);
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_sendUrgentData 
(JNIEnv *env, jobject, jint);
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_shutdownInput 
(JNIEnv *env, jobject);
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_shutdownOutput 
(JNIEnv *env, jobject);
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_unlink (JNIEnv 
*env, jobject);
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_localBind 
(JNIEnv *env, jobject, jobject);
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_localConnect 
(JNIEnv *env, jobject, jobject);
+JNIEXPORT jint JNICALL Java_gnu_java_net_local_LocalSocketImpl_read (JNIEnv 
*env, jobject, jbyteArray, jint, jint);
+JNIEXPORT void JNICALL Java_gnu_java_net_local_LocalSocketImpl_write (JNIEnv 
*env, jobject, jbyteArray, jint, jint);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gnu_java_net_local_LocalSocketImpl__ */
--- /dev/null   2006-04-12 17:45:39.000000000 -0700
+++ gnu/java/net/local/LocalServerSocket.java   2006-04-12 15:21:42.000000000 
-0700
@@ -0,0 +1,172 @@
+/* LocalServerSocket.java -- a unix domain server socket.
+   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.  */
+
+
+package gnu.java.net.local;
+
+import java.io.IOException;
+
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+
+public final class LocalServerSocket extends ServerSocket
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private LocalSocketImpl myImpl;
+  private boolean closed;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public LocalServerSocket () throws IOException
+  {
+    myImpl = new LocalSocketImpl ();
+  }
+
+  public LocalServerSocket (SocketAddress bindPoint) throws IOException
+  {
+    this ();
+    bind (bindPoint);
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public void bind (SocketAddress bindPoint) throws IOException
+  {
+    bind (bindPoint, 0);
+  }
+
+  public void bind (SocketAddress bindPoint, int backlog) throws IOException
+  {
+    myImpl.doCreate ();
+    myImpl.bind (bindPoint);
+    myImpl.listen (backlog);
+  }
+
+  public InetAddress getInetAddress ()
+  {
+    return null;
+  }
+
+  public int getLocalPort ()
+  {
+    return -1;
+  }
+
+  public SocketAddress getLocalSocketAddress ()
+  {
+    return myImpl.getLocalAddress ();
+  }
+
+  public Socket accept () throws IOException
+  {
+    LocalSocket s = new LocalSocket (true);
+    myImpl.accept (s.getLocalImpl());
+    s.localConnected = true;
+    return s;
+  }
+
+  public void close () throws IOException
+  {
+    myImpl.close ();
+    myImpl.unlink ();
+    closed = true;
+  }
+
+  public boolean isBound ()
+  {
+    return myImpl.getLocalAddress () != null;
+  }
+
+  public boolean isClosed ()
+  {
+    return closed;
+  }
+
+  public void setSoTimeout (int timeout)
+  {
+    throw new UnsupportedOperationException ("local sockets do not support 
timeouts");
+  }
+
+  public int getSoTimeout ()
+  {
+    throw new UnsupportedOperationException ("local sockets do not support 
timeouts");
+  }
+
+  public void setReuseAddress (boolean b)
+  {
+    throw new UnsupportedOperationException ("local sockets do not support 
reuse address");
+  }
+
+  public boolean getReuseAddress ()
+  {
+    throw new UnsupportedOperationException ("local sockets do not support 
reuse address");
+  }
+
+  public String toString ()
+  {
+    return LocalServerSocket.class.getName() + " [ address="
+      + myImpl.getLocalAddress() + " ]";
+  }
+
+  public void setReceiveBufferSize (int size)
+  {
+    throw new UnsupportedOperationException ("local sockets do not support 
buffer size");
+  }
+
+  public int getReceiveBufferSize ()
+  {
+    throw new UnsupportedOperationException ("local sockets do not support 
buffer size");
+  }
+
+  public void setSendBufferSize (int size)
+  {
+    throw new UnsupportedOperationException ("local sockets do not support 
buffer size");
+  }
+
+  public int getSendBufferSize ()
+  {
+    throw new UnsupportedOperationException ("local sockets do not support 
buffer size");
+  }
+}
--- /dev/null   2006-04-12 17:45:39.000000000 -0700
+++ gnu/java/net/local/LocalSocket.java 2006-04-12 15:33:08.000000000 -0700
@@ -0,0 +1,310 @@
+/* LocalSocket.java -- a unix domain client socket.
+   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.  */
+
+
+package gnu.java.net.local;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketImpl;
+
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.SocketChannel;
+
+/**
+ * A local, or unix-domain socket. Unix domain sockets are connected on the
+ * local filesystem itself, rather than a remote address.
+ */
+public final class LocalSocket extends Socket
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private final LocalSocketImpl localimpl;
+  boolean localClosed;
+  boolean localConnected;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public LocalSocket () throws SocketException
+  {
+    super ();
+    localimpl = new LocalSocketImpl ();
+  }
+
+  public LocalSocket (LocalSocketAddress addr) throws SocketException
+  {
+    this ();
+    try
+      {
+        connect (addr);
+      }
+    catch (IOException ioe)
+      {
+        throw new SocketException (ioe.getMessage ());
+      }
+  }
+
+  LocalSocket (boolean nocreate) throws IOException
+  {
+    super ();
+    localimpl = new LocalSocketImpl (nocreate);
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public void bind (SocketAddress bindpoint) throws IOException
+  {
+    throw new SocketException ("binding local client sockets is nonsensical");
+  }
+
+  public void connect (SocketAddress endpoint, int timeout) throws IOException
+  {
+    if (isClosed ())
+      {
+        throw new SocketException ("socket is closed");
+      }
+    if (! (endpoint instanceof LocalSocketAddress))
+      {
+        throw new IllegalArgumentException ("socket address is not a local 
address");
+      }
+    if (getChannel() != null && !getChannel().isBlocking())
+      {
+        throw new IllegalBlockingModeException ();
+      }
+
+    try
+      {
+        localimpl.doCreate ();
+        localimpl.localConnect ((LocalSocketAddress) endpoint);
+      }
+    catch (IOException ioe)
+      {
+        close ();
+        throw ioe;
+      }
+    localConnected = true;
+  }
+
+  public InetAddress getInetAddress ()
+  {
+    return null;
+  }
+
+  public InetAddress getLocalAddress ()
+  {
+    return null;
+  }
+
+  public int getPort ()
+  {
+    return -1;
+  }
+
+  public int getLocalPort ()
+  {
+    return -1;
+  }
+
+  public SocketChannel getChannel ()
+  {
+    return null;
+  }
+
+  public SocketAddress getLocalSocketAddress ()
+  {
+    return localimpl.getLocalAddress ();
+  }
+
+  public SocketAddress getRemoteSocketAddress ()
+  {
+    return localimpl.getRemoteAddress ();
+  }
+
+  public InputStream getInputStream () throws IOException
+  {
+    return localimpl.getInputStream ();
+  }
+
+  public OutputStream getOutputStream () throws IOException
+  {
+    return localimpl.getOutputStream ();
+  }
+
+  public void sendUrgentData (int b) throws IOException
+  {
+    localimpl.sendUrgentData (b);
+  }
+
+  public synchronized void close () throws IOException
+  {
+    localimpl.close ();
+    localClosed = true;
+  }
+
+  public void shutdownInput () throws IOException
+  {
+    localimpl.shutdownInput ();
+  }
+
+  public void shutdownOutput () throws IOException
+  {
+    localimpl.shutdownOutput ();
+  }
+
+  public boolean isClosed ()
+  {
+    return localClosed;
+  }
+
+  public boolean isBound ()
+  {
+    return false;
+  }
+
+  public boolean isConnected ()
+  {
+    return localConnected;
+  }
+
+  // Unsupported methods.
+  // -------------------------------------------------------------------------
+
+  public void setTcpNoDelay (boolean b) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public boolean getTcpNoDelay() throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public void setSoLinger (boolean b, int i) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public int getSoLinger () throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public void setOOBInline (boolean b) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public boolean getOOBInline () throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public void setSoTimeout (int i) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public int getSoTimeout () throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public void setSendBufferSize (int i) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public int getSendBufferSize() throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public void setReceiveBufferSize (int i) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public int getReceiveBufferSize () throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public void setKeepAlive (boolean b) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public boolean getKeepAlive () throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public void setTrafficClass (int i) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public int getTrafficClass () throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public void setReuseAddress (boolean b) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  public boolean getReuseAddress () throws SocketException
+  {
+    throw new SocketException ("local sockets do not support this option");
+  }
+
+  LocalSocketImpl getLocalImpl ()
+  {
+    return localimpl;
+  }
+}
--- /dev/null   2006-04-12 17:45:39.000000000 -0700
+++ gnu/java/net/local/LocalSocketAddress.java  2006-04-12 15:21:42.000000000 
-0700
@@ -0,0 +1,100 @@
+/* LocalSocketAddress.java -- unix-domain socket address.
+   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.  */
+
+
+package gnu.java.net.local;
+
+import java.net.SocketAddress;
+
+public final class LocalSocketAddress extends SocketAddress
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private final String path;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  /**
+   * Creates a new unix domain socket address.
+   *
+   * @param path The path to the socket.
+   * @throws NullPointerException If <i>path</i> is <tt>null</tt>.
+   */
+  public LocalSocketAddress (String path)
+  {
+    if (path == null)
+      {
+        throw new NullPointerException ();
+      }
+    this.path = path;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  /**
+   * Returns the path of the socket.
+   *
+   * @return The path.
+   */
+  public String getPath ()
+  {
+    return path;
+  }
+
+  public boolean equals (Object o)
+  {
+    if (!(o instanceof LocalSocketAddress))
+      {
+        return false;
+      }
+    return getPath ().equals (((LocalSocketAddress) o).getPath ());
+  }
+
+  public int hashCode ()
+  {
+    return path.hashCode();
+  }
+
+  public String toString ()
+  {
+    return LocalSocketAddress.class.getName() + " [ " + path + " ]";
+  }
+}
--- /dev/null   2006-04-12 17:45:39.000000000 -0700
+++ gnu/java/net/local/LocalSocketImpl.java     2006-04-12 17:05:16.000000000 
-0700
@@ -0,0 +1,322 @@
+/* LocalSocketImpl.java -- a unix domain client socket implementation.
+   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.  */
+
+
+package gnu.java.net.local;
+
+import java.io.FileDescriptor;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketImpl;
+
+final class LocalSocketImpl extends SocketImpl
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private boolean created;
+  private InputStream in;
+  private OutputStream out;
+  private int socket_fd;
+  private LocalSocketAddress local;
+  private LocalSocketAddress remote;
+
+  static
+  {
+    try
+      {
+        System.loadLibrary ("javanet");
+      }
+    catch (Exception x)
+      {
+        x.printStackTrace ();
+      }
+  }
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  LocalSocketImpl ()
+  {
+    this (false);
+  }
+
+  LocalSocketImpl (boolean nocreate)
+  {
+    created = nocreate;
+    socket_fd = -1;
+    fd = new FileDescriptor ();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public void setOption (int opt, Object value) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support options");
+  }
+
+  public Object getOption (int opt) throws SocketException
+  {
+    throw new SocketException ("local sockets do not support options");
+  }
+
+  protected native void create (boolean stream) throws IOException;
+  protected native void listen (int timeout) throws IOException;
+  protected native void accept (LocalSocketImpl socket) throws IOException;
+  protected native int available () throws IOException;
+  protected native void close () throws IOException;
+  protected native void sendUrgentData (int data) throws IOException;
+  protected native void shutdownInput () throws IOException;
+  protected native void shutdownOutput () throws IOException;
+
+  native void unlink () throws IOException;
+  native void localBind (LocalSocketAddress addr) throws IOException;
+  native void localConnect (LocalSocketAddress addr) throws IOException;
+  native int read (byte[] buf, int off, int len) throws IOException;
+  native void write (byte[] buf, int off, int len) throws IOException;
+
+  void doCreate () throws IOException
+  {
+    if (!created)
+      {
+        create (true);
+      }
+  }
+
+  LocalSocketAddress getLocalAddress ()
+  {
+    return local;
+  }
+
+  LocalSocketAddress getRemoteAddress ()
+  {
+    return remote;
+  }
+
+  protected InputStream getInputStream()
+  {
+    if (in == null)
+      {
+        in = new LocalInputStream (this);
+      }
+
+    return in;
+  }
+
+  protected OutputStream getOutputStream()
+  {
+    if (out == null)
+      {
+        out = new LocalOutputStream (this);
+      }
+
+    return out;
+  }
+
+  protected void accept (SocketImpl impl) throws IOException
+  {
+    if (! (impl instanceof LocalSocketImpl))
+      {
+        throw new IllegalArgumentException ("not a local socket");
+      }
+    accept ((LocalSocketImpl) impl);
+  }
+
+  protected void connect (String host, int port) throws IOException
+  {
+    throw new SocketException ("this is a local socket");
+  }
+
+  protected void connect (InetAddress addr, int port) throws IOException
+  {
+    throw new SocketException ("this is a local socket");
+  }
+
+  protected void connect(SocketAddress addr, int timeout) throws IOException
+  {
+    if (! (addr instanceof LocalSocketAddress))
+      {
+        throw new SocketException ("address is not local");
+      }
+    localConnect ((LocalSocketAddress) addr);
+  }
+
+  protected void bind (InetAddress addr, int port) throws IOException
+  {
+    throw new SocketException ("this is a local socket");
+  }
+
+  protected void bind (SocketAddress addr) throws IOException
+  {
+    if (! (addr instanceof LocalSocketAddress))
+      {
+        throw new SocketException ("address is not local");
+      }
+    localBind ((LocalSocketAddress) addr);
+  }
+
+// Inner classes.
+  // -------------------------------------------------------------------------
+
+  class LocalInputStream extends InputStream
+  {
+
+    // Field.
+    // -----------------------------------------------------------------------
+
+    private final LocalSocketImpl impl;
+
+    // Constructor.
+    // -----------------------------------------------------------------------
+
+    LocalInputStream (LocalSocketImpl impl)
+    {
+      this.impl = impl;
+    }
+
+    // Instance methods.
+    // -----------------------------------------------------------------------
+
+    public int available () throws IOException
+    {
+      return impl.available();
+    }
+
+    public boolean markSupported ()
+    {
+      return false;
+    }
+
+    public void mark (int readLimit)
+    {
+    }
+
+    public void reset () throws IOException
+    {
+      throw new IOException ("mark/reset not supported");
+    }
+
+    public void close () throws IOException
+    {
+      impl.close();
+    }
+
+    public int read () throws IOException
+    {
+      byte[] buf = new byte[1];
+      int ret = read (buf);
+      if (ret != -1)
+        {
+          return buf[0] & 0xFF;
+        }
+      else
+        {
+          return -1;
+        }
+    }
+
+    public int read (byte[] buf) throws IOException
+    {
+      return read (buf, 0, buf.length);
+    }
+
+    public int read (byte[] buf, int off, int len) throws IOException
+    {
+      int ret = impl.read (buf, off, len);
+
+      if (ret == 0)
+        {
+          return -1;
+        }
+
+      return ret;
+    }
+  }
+
+  class LocalOutputStream extends OutputStream
+  {
+
+    // Field.
+    // -----------------------------------------------------------------------
+
+    private final LocalSocketImpl impl;
+
+    // Constructor.
+    // -----------------------------------------------------------------------
+
+    LocalOutputStream (LocalSocketImpl impl)
+    {
+      this.impl = impl;
+    }
+
+    // Instance methods.
+    // -----------------------------------------------------------------------
+
+    public void close () throws IOException
+    {
+      impl.close ();
+    }
+
+    public void flush () throws IOException
+    {
+    }
+
+    public void write (int b) throws IOException
+    {
+      byte[] buf = new byte [1];
+      buf[0] = (byte) b;
+      write (buf);
+    }
+
+    public void write (byte[] buf) throws IOException
+    {
+      write (buf, 0, buf.length);
+    }
+
+    public void write (byte[] buf, int off, int len) throws IOException
+    {
+      impl.write (buf, off, len);
+    }
+  }
+}
--- /dev/null   2006-04-12 17:45:39.000000000 -0700
+++ native/jni/java-net/gnu_java_net_local_LocalSocketImpl.c    2006-04-12 
17:50:55.000000000 -0700
@@ -0,0 +1,470 @@
+/* gnu_java_net_local_LocalSocketImpl.c -- native local socket implementation.
+   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.  */
+
+
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#define ENABLE_LOCAL_SOCKETS
+#ifdef ENABLE_LOCAL_SOCKETS
+
+#include <gnu_java_net_local_LocalSocketImpl.h>
+
+#include <stddef.h>
+#include "local.h"
+
+#define TRACE(msg) fprintf (stderr, "%s(%s:%d) -- %s\n", __FUNCTION__, 
__FILE__, __LINE__, msg)
+
+static void
+_throw (JNIEnv *env, const char *exception, const char *msg)
+{
+  jclass _theclass = (*env)->FindClass (env, exception);
+  TRACE("begin");
+  if (!_theclass)
+    {
+      (*env)->FatalError (env, "exception class not found");
+    }
+  (*env)->ThrowNew (env, _theclass, msg);
+  TRACE("end");
+}
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_create (JNIEnv *env, jobject this, 
jboolean stream)
+{
+  jfieldID socket_fd, created;
+  jclass clazz;
+  jint fd = (jint) local_create ((int) stream);
+
+  TRACE("begin");
+
+  if (fd < 0)
+    {
+      _throw (env, "java/io/IOException", local_error ());
+      return;
+    }
+  clazz = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return;
+    }
+  created = (*env)->GetFieldID (env, clazz, "created", "Z");
+  if (!created)
+    {
+      return;
+    }
+  (*env)->SetIntField (env, this, socket_fd, fd);
+  (*env)->SetBooleanField (env, this, created, JNI_TRUE);
+
+  TRACE("end");
+}
+
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_listen (JNIEnv *env, jobject this, 
jint backlog)
+{
+  jfieldID socket_fd;
+  jclass clazz;
+  int fd;
+
+  TRACE("begin");
+
+  clazz = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return;
+    }
+  fd = (int) (*env)->GetIntField (env, this, socket_fd);
+  if (local_listen (fd, (int) backlog))
+    {
+      _throw (env, "java/io/IOException", local_error ());
+      return;
+    }
+
+  TRACE("end");
+}
+
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_accept (JNIEnv *env, jobject this, 
jobject socket)
+{
+  jmethodID addr_init;
+  jfieldID socket_fd, remote_addr, local_addr;
+  jclass clazz1, clazz2;
+  jobject remote, local;
+  jint fd;
+  char path[108];
+
+  TRACE("begin");
+
+  clazz1 = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz1, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return;
+    }
+  fd = (*env)->GetIntField (env, this, socket_fd);
+  fd = (jint) local_accept ((int) fd, path);
+  if (fd < 0)
+    {
+      _throw (env, "java/io/IOException", local_error ());
+      return;
+    }
+
+  clazz2 = (*env)->FindClass (env, "gnu/java/net/local/LocalSocketAddress");
+  if (!clazz2)
+    {
+      return;
+    }
+  addr_init = (*env)->GetMethodID (env, clazz2, "<init>", 
"(Ljava/lang/String;)V");
+  if (!addr_init)
+    {
+      return;
+    }
+  remote = (*env)->NewObject (env, clazz2, addr_init, (*env)->NewStringUTF 
(env, path));
+
+  remote_addr = (*env)->GetFieldID (env, clazz1, "remote", 
"Lgnu/java/net/local/LocalSocketAddress;");
+  if (!remote_addr)
+    {
+      return;
+    }
+  local_addr = (*env)->GetFieldID (env, clazz1, "local", 
"Lgnu/java/net/local/LocalSocketAddress;");
+  if (!local_addr)
+    {
+      return;
+    }
+  local = (*env)->GetObjectField (env, this, local_addr);
+  (*env)->SetIntField (env, socket, socket_fd, fd);
+  (*env)->SetObjectField (env, socket, remote_addr, remote);
+  (*env)->SetObjectField (env, socket, local_addr, local);
+
+  TRACE("end");
+}
+
+
+jint
+Java_gnu_java_net_local_LocalSocketImpl_available (JNIEnv *env, jobject this)
+{
+  jfieldID socket_fd;
+  jclass clazz;
+  jint avail;
+
+  TRACE("begin");
+
+  clazz = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return 0;
+    }
+  avail = (jint) local_available ((int) (*env)->GetIntField (env, this, 
socket_fd));
+  if (avail < 0)
+    {
+      _throw (env, "java/io/IOException", local_error ());
+      return 0;
+    }
+
+  TRACE("end");
+
+  return avail;
+}
+
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_close (JNIEnv *env, jobject this)
+{
+  jfieldID socket_fd;
+  jclass clazz;
+  int fd;
+
+  TRACE("begin");
+
+  clazz = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return;
+    }
+  fd = (int) (*env)->GetIntField (env, this, socket_fd);
+  if (local_close (fd))
+    {
+      _throw (env, "java/io/IOException", local_error ());
+    }
+
+  TRACE("end");
+}
+
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_unlink (JNIEnv *env, jobject this)
+{
+  jfieldID local;
+  jmethodID get_path;
+  jclass clazz1, clazz2;
+  jobject local_ref, path;
+  char *addr_path;
+
+  TRACE("begin");
+
+  clazz1 = (*env)->GetObjectClass (env, this);
+  local = (*env)->GetFieldID (env, clazz1, "local", 
"Lgnu/java/net/local/LocalSocketAddress;");
+  if (!local)
+    {
+      return;
+    }
+  local_ref = (*env)->GetObjectField (env, this, local);
+  clazz2 = (*env)->GetObjectClass (env, local_ref);
+  get_path = (*env)->GetMethodID (env, clazz2, "getPath", 
"()Ljava/lang/String;");
+  if (!get_path)
+    {
+      return;
+    }
+  path = (*env)->CallObjectMethod (env, local_ref, get_path);
+  addr_path = (char *) (*env)->GetStringUTFChars (env, (jstring) path, NULL);
+  if (local_unlink (addr_path))
+    {
+      _throw (env, "java/io/IOException", local_error ());
+    }
+  (*env)->ReleaseStringUTFChars (env, (jstring) path, addr_path);
+
+  TRACE("end");
+}
+
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_sendUrgentData (JNIEnv *env, jobject 
this __attribute__((unused)), jint data __attribute__((unused)))
+{
+  (*env)->FatalError (env, 
"Java_gnu_java_net_local_LocalSocketImpl_shutdownInput (JNIEnv *env, jobject) 
not implemented");
+}
+
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_shutdownInput (JNIEnv *env, jobject 
this)
+{
+  jfieldID socket_fd;
+  jclass clazz;
+  int fd;
+
+  TRACE("begin");
+
+  clazz = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return;
+    }
+  fd = (*env)->GetIntField (env, this, socket_fd);
+  if (local_shutdown_input (fd))
+    {
+      _throw (env, "java/io/IOException", local_error ());
+    }
+
+  TRACE("end");
+}
+
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_shutdownOutput (JNIEnv *env, jobject 
this)
+{
+  jfieldID socket_fd;
+  jclass clazz;
+  int fd;
+
+  TRACE("begin");
+
+  clazz = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return;
+    }
+  fd = (*env)->GetIntField (env, this, socket_fd);
+  if (local_shutdown_output (fd))
+    {
+      _throw (env, "java/io/IOException", local_error ());
+    }
+
+  TRACE("end");
+}
+
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_localBind (JNIEnv *env, jobject this, 
jobject address)
+{
+  jfieldID socket_fd;
+  jmethodID get_path;
+  jobject path;
+  jclass clazz1, clazz2;
+  char *addr_path;
+  int fd;
+  jboolean copied;
+
+  TRACE("begin");
+
+  clazz1 = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz1, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return;
+    }
+  fd = (int) (*env)->GetIntField (env, this, socket_fd);
+  clazz2 = (*env)->GetObjectClass (env, address);
+  get_path = (*env)->GetMethodID (env, clazz2, "getPath", 
"()Ljava/lang/String;");
+  path = (*env)->CallObjectMethod (env, address, get_path);
+  addr_path = (char *) (*env)->GetStringUTFChars (env, (jstring) path, 
&copied);
+  fprintf (stderr, "got UTF bytes %p\n", addr_path);
+  if (local_bind (fd, addr_path))
+    {
+      _throw (env, "java/io/IOException", local_error ());
+    }
+  TRACE("ReleaseStringUTFChars");
+  fprintf (stderr, "release UTF bytes %p\n", addr_path);
+  (*env)->ReleaseStringUTFChars (env, (jstring) path, addr_path);
+  
+  TRACE("end ReleaseStringUTFChars");
+
+  TRACE("end");
+}
+
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_localConnect (JNIEnv *env, jobject 
this, jobject address)
+{
+  jfieldID socket_fd;
+  jmethodID get_path;
+  jobject path;
+  jclass clazz1, clazz2;
+  char *addr_path;
+  int fd;
+
+  TRACE("begin");
+
+  clazz1 = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz1, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return;
+    }
+  fd = (int) (*env)->GetIntField (env, this, socket_fd);
+  clazz2 = (*env)->GetObjectClass (env, address);
+  get_path = (*env)->GetMethodID (env, clazz2, "getPath", 
"()Ljava/lang/String;");
+  path = (*env)->CallObjectMethod (env, address, get_path);
+  addr_path = (char *) (*env)->GetStringUTFChars (env, (jstring) path, NULL);
+  if (local_connect (fd, addr_path))
+    {
+      _throw (env, "java/io/IOException", local_error ());
+    }
+  (*env)->ReleaseStringUTFChars (env, (jstring) path, addr_path);
+
+  TRACE("end");
+}
+
+
+jint
+Java_gnu_java_net_local_LocalSocketImpl_read (JNIEnv *env, jobject this, 
jbyteArray buf, jint off, jint len)
+{
+  jfieldID socket_fd;
+  jclass clazz;
+  jbyte *buffer;
+  jint count;
+  int fd;
+
+  TRACE("begin");
+
+  if (off < 0 || len < 0 || off + len > (*env)->GetArrayLength (env, buf))
+    {
+      _throw (env, "java/lang/ArrayIndexOutOfBoundsException", "");
+    }
+
+  clazz = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return 0;
+    }
+  fd = (int) (*env)->GetIntField (env, this, socket_fd);
+  buffer = (*env)->GetByteArrayElements (env, buf, NULL);
+  count = (jint) local_read (fd, (void *) (buffer + off), (int) len);
+  if (count < 0)
+    {
+      _throw (env, "java/io/IOException", local_error ());
+    }
+  (*env)->ReleaseByteArrayElements (env, buf, buffer, 0);
+
+  TRACE("end");
+
+  return count;
+}
+
+
+void
+Java_gnu_java_net_local_LocalSocketImpl_write (JNIEnv *env, jobject this, 
jbyteArray buf, jint off, jint len)
+{
+  jfieldID socket_fd;
+  jclass clazz;
+  jbyte *buffer;
+  int fd;
+
+  TRACE("begin");
+
+  if (off < 0 || len < 0 || off + len > (*env)->GetArrayLength (env, buf))
+    {
+      _throw (env, "java/lang/ArrayIndexOutOfBoundsException", "");
+    }
+
+  clazz = (*env)->GetObjectClass (env, this);
+  socket_fd = (*env)->GetFieldID (env, clazz, "socket_fd", "I");
+  if (!socket_fd)
+    {
+      return;
+    }
+  fd = (int) (*env)->GetIntField (env, this, socket_fd);
+  buffer = (*env)->GetByteArrayElements (env, buf, NULL);
+  if (local_write (fd, (void *) (buffer + off), (int) len) < 0)
+    {
+      _throw (env, "java/io/IOException", local_error ());
+    }
+  (*env)->ReleaseByteArrayElements (env, buf, buffer, JNI_ABORT);
+
+  TRACE("end");
+}
+
+#endif /* ENABLE_LOCAL_SOCKETS */
--- /dev/null   2006-04-12 17:45:39.000000000 -0700
+++ native/jni/java-net/local.c 2006-04-12 17:45:20.000000000 -0700
@@ -0,0 +1,160 @@
+/* local.c -- implementation of unix-domain sockets.
+   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.  */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <stdio.h>
+
+#include "local.h"
+
+const char *
+local_error (void)
+{
+  return strerror (errno);
+}
+
+int
+local_create (int stream)
+{
+  return socket (PF_UNIX, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
+}
+
+int
+local_bind (int fd, const char *addr)
+{
+  struct sockaddr_un saddr;
+
+  fprintf (stderr, "local bind addr=%p\n", addr);
+
+  strncpy (saddr.sun_path, addr, sizeof (saddr.sun_path));
+  saddr.sun_path[sizeof (saddr.sun_path)] = '\0';
+  saddr.sun_family = AF_LOCAL;
+
+  fprintf (stderr, "local bind done addr=%p\n", addr);  
+
+  return bind (fd, (struct sockaddr *) &saddr, SUN_LEN (&saddr));
+}
+
+int
+local_listen (int fd, int backlog)
+{
+  return listen (fd, backlog);
+}
+
+int
+local_accept (int fd, char *path)
+{
+  int newfd;
+  struct sockaddr_un addr;
+  socklen_t sz = SUN_LEN(&addr);
+
+  newfd = accept (fd, (struct sockaddr *) &addr, &sz);
+  if (newfd >= 0)
+    {
+      strncpy (path, addr.sun_path, 107);
+      path[107] = '\0';
+    }
+  return newfd;
+}
+
+int
+local_available (int fd)
+{
+  int val;
+  if (ioctl (fd, FIONREAD, &val))
+    {
+      return -1;
+    }
+  return val;
+}
+
+int
+local_close (int fd)
+{
+  return close (fd);
+}
+
+int
+local_unlink (char *path)
+{
+  return unlink (path);
+}
+
+int
+local_shutdown_input (int fd)
+{
+  return shutdown (fd, 0);
+}
+
+int
+local_shutdown_output (int fd)
+{
+  return shutdown (fd, 1);
+}
+
+int
+local_connect (int fd, char *path)
+{
+  struct sockaddr_un saddr;
+
+  strncpy (saddr.sun_path, path, sizeof (saddr.sun_path));
+  saddr.sun_path[sizeof (saddr.sun_path) - 1] = '\0';
+  saddr.sun_family = AF_UNIX;
+
+  return connect (fd, (struct sockaddr *) &saddr, SUN_LEN(&saddr));
+}
+
+int
+local_read (int fd, void *buf, int len)
+{
+  return read (fd, buf, len);
+}
+
+int
+local_write (int fd, void *buf, int len)
+{
+  return write (fd, buf, len);
+}
--- /dev/null   2006-04-12 17:45:39.000000000 -0700
+++ native/jni/java-net/local.h 2006-04-12 15:34:23.000000000 -0700
@@ -0,0 +1,28 @@
+#ifndef __LOCAL_H__
+#define __LOCAL_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#define __EMACSEN__ }
+
+extern const char *local_error (void);
+extern int local_create (int);
+extern int local_bind (int, const char *);
+extern int local_listen (int, int);
+extern int local_accept (int, char *);
+extern int local_available (int);
+extern int local_close (int);
+extern int local_shutdown_input (int);
+extern int local_shutdown_output (int);
+extern int local_connect (int, char *);
+extern int local_unlink (char *);
+extern int local_read (int, void *, int);
+extern int local_write (int, void *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LOCAL_H__ */
Index: include/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/include/Makefile.am,v
retrieving revision 1.55
diff -r1.55 Makefile.am
121a122
> $(top_srcdir)/include/gnu_java_net_local_LocalSocketImpl.h \
209a211,213
> $(top_srcdir)/include/gnu_java_net_local_LocalSocketImpl.h: 
> $(top_srcdir)/gnu/java/net/local/LocalSocketImpl.h
>       $(JAVAH) -o $@ gnu.java.net.local.LocalSocketImpl
> 
Index: native/jni/java-net/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/java-net/Makefile.am,v
retrieving revision 1.14
diff -r1.14 Makefile.am
8c8,11
<                         gnu_java_net_VMPlainSocketImpl.c
---
>                         gnu_java_net_VMPlainSocketImpl.c \
>                       gnu_java_net_local_LocalSocketImpl.c \
>                       local.c \
>                       local.h

Reply via email to