This is the mail archive of the java-discuss@sourceware.cygnus.com mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[patch #3] java.net stuff


Here's a patch for java.net that implements some of the socket options
methods which are often use by server-type applications.

I am pleased to report that ORBacus (www.orbacus.com) is now working
great on gcj, and starts up quicker and uses a lot less memory than
under the Java VM. I have both libgcj and ORBacus compiled as shared
libs, and the server binaries built against these come out fairly small.

Changelog:

- natPlainSocketImpl.cc (connect) - make sure that the actual localport
gets set when an outgoing socket gets connected
- ServerSocket.java - fix name of ServerSocket.setSocketFactory() (it
wasn't consistant with JDK 1.2 docs)
- fix misc typos
- ServerSocket.java & Socket.java - implement toString() methods
- Socket.java (getLocalAddress) - implemented
- Socket.java - implement socket options methods: set&getTcpNoDelay(),
set/getSoLinger(), set/getSendBufferSize(), set/getReceiveBufferSize
- add java.net.SocketOptions interface specifying low-level
PlainSocketImpl.setOption() & getOption()
- natPlainSocketImpl.cc (setOption, getOption) - native implementation
of socket options methods

In addition, I have implemented the set/getSoTimeout() methods in
Socket.java and ServerSocket.java. However, this option is not
implemented in the native code, and will currently throw an exception.
Actually, it might be better to implement socket timeouts in libgcj
itself rather than trying to set parameters in the TCP stack to do it,
because apparantly the timeouts don't work on most platforms (they
certainly didnt work for me). Kaffe appears to implement timeouts
itself.

Note that you'll need to add the new SocketOptions.java to
libjava/Makefile.am

enjoy

  [ bryce ]

Index: java/net/PlainSocketImpl.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/net/PlainSocketImpl.java,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 PlainSocketImpl.java
--- PlainSocketImpl.java	1999/04/07 14:52:40	1.1.1.1
+++ PlainSocketImpl.java	1999/04/21 11:17:45
@@ -1,5 +1,3 @@
-// natClass.cc - Implementation of java.lang.Class native methods.
-
 /* Copyright (C) 1998, 1999  Cygnus Solutions
 
    This file is part of libgcj.
@@ -13,6 +11,15 @@
 
 class PlainSocketImpl extends SocketImpl
 {
+  static final int _Jv_IP_MULTICAST_IF_ = SocketOptions.IP_MULTICAST_IF,
+		   _Jv_SO_BINDADDR_ = SocketOptions.SO_BINDADDR,
+		   _Jv_SO_LINGER_ = SocketOptions.SO_LINGER,
+		   _Jv_SO_SNDBUF_ = SocketOptions.SO_SNDBUF,
+		   _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF,
+		   _Jv_SO_REUSEADDR_ = SocketOptions.SO_REUSEADDR,
+		   _Jv_SO_TIMEOUT_ = SocketOptions.SO_TIMEOUT,
+		   _Jv_TCP_NODELAY_ = SocketOptions.TCP_NODELAY;
+
   int fnum = -1;
 
   protected native void create (boolean stream)  throws IOException;
@@ -61,4 +68,8 @@
   {
     fd.close();
   }
+  
+  public native void setOption (int optID, Object value) throws SocketException;
+
+  public native Object getOption (int optID) throws SocketException;
 }
Index: java/net/ServerSocket.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/net/ServerSocket.java,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ServerSocket.java
--- ServerSocket.java	1999/04/07 14:52:40	1.1.1.1
+++ ServerSocket.java	1999/04/21 11:17:45
@@ -1,5 +1,3 @@
-// Socket.java
-
 /* Copyright (C) 1999  Cygnus Solutions
 
    This file is part of libgcj.
@@ -14,8 +12,7 @@
   */
 
 /** Written using on-line Java Platform 1.2 API Specification.
-  * Status:  I believe all methods are implemented, but many
-  * of them just throw an exception.
+  * Status:  I believe all methods are implemented
   */
 
 package java.net;
@@ -83,20 +80,27 @@
 
   public void setSoTimeout (int timeout) throws SocketException
   {
-    throw new InternalError("ServerSocket.setSoTimeout not implemented");
+    if (timeout >= 0)
+      impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+    else
+      throw new IllegalArgumentException("SO_TIMEOUT must be >= 0");
   }
 
   public int getSoTimeout () throws SocketException
   {
-    throw new InternalError("ServerSocket.getSoTimeout not implemented");
+    Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT);
+    if (timeout instanceof Integer) 
+      return ((Integer)timeout).intValue();
+    else
+      return 0;
   }
 
   public String toString ()
   {
-    return impl.toString();
+    return "ServerSocket" + impl.toString();
   }
 
-  public static void setSocketImplFactory (SocketImplFactory fac)
+  public static void setSocketFactory (SocketImplFactory fac)
     throws IOException
   {
     factory = fac;
Index: java/net/Socket.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/net/Socket.java,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 Socket.java
--- Socket.java	1999/04/07 14:52:40	1.1.1.1
+++ Socket.java	1999/04/21 11:17:45
@@ -14,8 +14,9 @@
   */
 
 /** Written using on-line Java Platform 1.2 API Specification.
-  * Status:  I believe all methods are implemented, but many
-  * of them just throw an exception.
+  * Status:  I believe all methods are implemented. 
+  * getSoTimeout() and setSoTimeout() are implemented here but won't work
+  * until they are supported by PlainSocketImpl
   */
 
 package java.net;
@@ -116,9 +117,18 @@
 
   public InetAddress getLocalAddress ()
   {
-    // There doesn't seem to be any way to implement this
-    // using a (generic) SocketImpl ...  What am I missing?
-    throw new InternalError("Socket.getLocalAddres not implemented");
+    InetAddress localAddress;
+    try 
+      {
+	localAddress = (InetAddress)impl.getOption(SocketOptions.SO_BINDADDR);
+      } 
+    catch (SocketException x) 
+      {
+	// (hopefully) shouldn't happen
+	System.err.println(x);
+        throw new java.lang.InternalError("Error in PlainSocketImpl.getOption");
+      };
+    return localAddress;
   }
 
   public int getPort ()
@@ -143,52 +153,81 @@
 
   public void setTcpNoDelay (boolean on)  throws SocketException
   {
-    throw new InternalError("Socket.setTcpNoDelay not implemented");
+    impl.setOption( SocketOptions.TCP_NODELAY, new Boolean(on) );
   }
 
   public boolean getTcpNoDelay() throws SocketException
   {
-    throw new InternalError("Socket.getTcpNoDelay not implemented");
+    Boolean bool = (Boolean)impl.getOption( SocketOptions.TCP_NODELAY );
+    return bool.booleanValue();
   }
 
   public void setSoLinger(boolean on, int linger) throws SocketException
   {
-    throw new InternalError("Socket.setSoLinger not implemented");
+    if ( on && (linger >= 0) ) 
+    {
+      if (linger > 65535)
+        linger = 65535;
+      impl.setOption( SocketOptions.SO_LINGER, new Integer(linger) );
+    } 
+    else if ( on && (linger < 0) ) 
+      throw new IllegalArgumentException("SO_LINGER must be >= 0");
+    else
+      impl.setOption( SocketOptions.SO_LINGER, new Boolean(false) );
+  }
+
+  public int getSoLinger() throws SocketException
+  {
+    Object linger = impl.getOption(SocketOptions.SO_LINGER);    
+    if (linger instanceof Integer) 
+      return ((Integer)linger).intValue();
+    else
+      return -1;
   }
 
-  public boolean getSoLinger() throws SocketException
-  {
-    throw new InternalError("Socket.getSoLinger not implemented");
-  }
-
   public void setSoTimeout (int timeout) throws SocketException
   {
-    throw new InternalError("Socket.setSoTimeout not implemented");
+    if (timeout >= 0)
+      impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+    else
+      throw new IllegalArgumentException("SO_TIMEOUT must be >= 0");
   }
 
   public int getSoTimeout () throws SocketException
   {
-    throw new InternalError("Socket.getSoTimeout not implemented");
+    Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT);
+    if (timeout instanceof Integer) 
+      return ((Integer)timeout).intValue();
+    else
+      return 0;
   }
 
   public void setSendBufferSize (int size) throws SocketException
   {
-    throw new InternalError("Socket.setSendBufferSize not implemented");
+    if (size > 0)
+      impl.setOption(SocketOptions.SO_SNDBUF, new Integer(size));    
+    else
+      throw new IllegalArgumentException("SO_SNDBUF must be > 0");
   }
 
   public int getSendBufferSize () throws SocketException
   {
-    throw new InternalError("Socket.getSendBufferSize not implemented");
+    Integer buf = (Integer)impl.getOption(SocketOptions.SO_SNDBUF);
+    return buf.intValue();
   }
 
   public void setReceiveBufferSize (int size) throws SocketException
   {
-    throw new InternalError("Socket.setReceiveBufferSize not implemented");
+    if (size > 0)
+      impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size));    
+    else
+      throw new IllegalArgumentException("SO_RCVBUF must be > 0");
   }
 
   public int getReceiveBufferSize () throws SocketException
   {
-    throw new InternalError("Socket.getReceiveBufferSize not implemented");
+    Integer buf = (Integer)impl.getOption(SocketOptions.SO_RCVBUF);
+    return buf.intValue();
   }
 
   public void close ()  throws IOException
@@ -198,7 +237,7 @@
 
   public String toString ()
   {
-    return impl.toString();
+    return "Socket" + impl.toString();
   }
 
   public static void setSocketImplFactory (SocketImplFactory fac)
Index: java/net/SocketImpl.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/net/SocketImpl.java,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 SocketImpl.java
--- SocketImpl.java	1999/04/07 14:52:40	1.1.1.1
+++ SocketImpl.java	1999/04/21 11:17:46
@@ -17,10 +17,10 @@
   */
 
 /** Written using on-line Java Platform 1.2 API Specification.
-  * Believed complete and correct, except for implementation of toString.
+  * Believed complete and correct.
   */
 
-public abstract class SocketImpl
+public abstract class SocketImpl implements SocketOptions
 {
   protected InetAddress address;
 
@@ -63,8 +63,14 @@
 
   protected int getLocalPort () { return localport; }
 
+  public abstract Object getOption(int optID) throws SocketException;
+		 
+  public abstract void setOption(int optID, Object value) throws SocketException;
+  
   public String toString ()
   {
-    return super.toString();  // FIXME
+    return "[addr=" + address.toString() + ",port=" + 
+      Integer.toString(port) + ",localport=" + Integer.toString(localport) 
+      + "]";
   }
 }
Index: java/net/natInetAddress.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/net/natInetAddress.cc,v
retrieving revision 1.3
diff -u -r1.3 natInetAddress.cc
--- natInetAddress.cc	1999/04/14 11:07:51	1.3
+++ natInetAddress.cc	1999/04/21 11:17:46
@@ -1,5 +1,3 @@
-// natClass.cc - Implementation of java.lang.Class native methods.
-
 /* Copyright (C) 1998, 1999  Cygnus Solutions
 
    This file is part of libgcj.
Index: java/net/natPlainSocketImpl.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/net/natPlainSocketImpl.cc,v
retrieving revision 1.2
diff -u -r1.2 natPlainSocketImpl.cc
--- natPlainSocketImpl.cc	1999/04/08 13:22:59	1.2
+++ natPlainSocketImpl.cc	1999/04/21 11:17:46
@@ -11,15 +11,23 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 
 #include <cni.h>
+#include <javaprims.h>
 #include <java/io/IOException.h>
 #include <java/io/FileDescriptor.h>
 #include <java/net/PlainSocketImpl.h>
 #include <java/net/InetAddress.h>
+#include <java/net/SocketException.h>
+#include <java/lang/Object.h>
+#include <java/lang/Boolean.h>
+#include <java/lang/Class.h>
+#include <java/lang/Integer.h>
+#include <java/lang/InternalError.h>
 
 #ifndef HAVE_SOCKLEN_T
 typedef int socklen_t;
@@ -64,7 +72,7 @@
       u.address.sin_port = htons (lport);
     }
 #ifdef HAVE_INET6
-  else if (len == 16)
+  else if (len == 16) 
     {
       u.address6.sin6_family = AF_INET6;
       memcpy (&u.address6.sin6_addr, bytes, len);
@@ -91,6 +99,7 @@
 java::net::PlainSocketImpl::connect (java::net::InetAddress *host, jint rport)
 {
   union SockAddr u;
+  socklen_t addrlen = sizeof(u);  
   jbyteArray haddress = host->address;
   jbyte *bytes = elements (haddress);
   int len = haddress->length;
@@ -113,12 +122,14 @@
 #endif
   else
     goto error;
-  if (::connect (fnum, ptr, len) == 0)
-    {
-      address = host;
-      port = rport;
-      return;
-    }
+  if (::connect (fnum, ptr, len) != 0)
+    goto error;
+  address = host;
+  port = rport;
+  if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
+    goto error;
+  localport = ntohs (u.address.sin_port);
+  return;  
  error:
   char msg[100];
   char* strerr = strerror (errno);
@@ -175,4 +186,173 @@
   char* strerr = strerror (errno);
   sprintf (msg, "SocketImpl.accept: %.*s", 80, strerr);
   JvThrow (new java::io::IOException (JvNewStringUTF (msg)));
+}
+
+void 
+java::net::PlainSocketImpl::setOption (jint optID, java::lang::Object *value) 
+{
+  int val;
+  socklen_t val_len = sizeof (val);
+  if ( _Jv_IsInstanceOf(value,
+      java::lang::Class::forName(JvNewStringUTF("java.lang.Boolean"))))
+  {
+    java::lang::Boolean *boolobj = 
+      static_cast<java::lang::Boolean *> (value);
+    if (boolobj->booleanValue()) val = 1; 
+      else 
+      {
+        if (optID == _Jv_SO_LINGER_) val = -1;
+        else val = 0;
+      }
+  }
+  else  // assume value is an Integer
+  {
+    java::lang::Integer *intobj = 
+      static_cast<java::lang::Integer *> (value);          
+    val = (int) intobj->intValue();
+  }
+  switch (optID) 
+  {
+    case _Jv_TCP_NODELAY_ :
+#ifdef TCP_NODELAY
+      if (::setsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, 
+                        &val, val_len) != 0) goto error;    
+#else
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("TCP_NODELAY not supported")));      
+#endif /* TCP_NODELAY */			
+      return;
+    case _Jv_SO_LINGER_ :
+#ifdef SO_LINGER
+      struct linger l_val;
+      l_val.l_onoff = (val != -1);
+      l_val.l_linger = val;
+      if (::setsockopt (fnum, SOL_SOCKET, SO_LINGER, 
+                        &l_val, sizeof(l_val)) != 0) goto error;    
+#else
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("SO_LINGER not supported")));      	
+#endif /* SO_LINGER */
+      return;
+    case _Jv_SO_SNDBUF_ :
+    case _Jv_SO_RCVBUF_ :
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+      int opt;
+      optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+        if (::setsockopt (fnum, SOL_SOCKET, opt, 
+ 	                  &val, val_len) != 0) goto error;    
+#else
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported")));
+#endif 
+      return;
+    case _Jv_SO_BINDADDR_ :
+      JvThrow (new java::net::SocketException (
+        JvNewStringUTF ("SO_BINDADDR: read only option")));
+      return;
+    case _Jv_IP_MULTICAST_IF_ :
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("IP_MULTICAST_IF not implemented")));
+      return;
+    case _Jv_SO_REUSEADDR_ :
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("SO_REUSEADDR: option not implemented")));
+      return;
+    case _Jv_SO_TIMEOUT_ :
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("SO_TIMEOUT: option not implemented")));
+      return;
+  }
+
+  error:
+    char msg[100];
+    char* strerr = strerror (errno);
+    sprintf (msg, "SocketImpl.setOption: %.*s", 75, strerr);
+    JvThrow (new java::net::SocketException (JvNewStringUTF (msg)));
+}
+
+java::lang::Object *
+java::net::PlainSocketImpl::getOption (jint optID)
+{  
+  int val;
+  socklen_t val_len = sizeof(val);
+  union SockAddr u;
+  socklen_t addrlen = sizeof(u);
+  struct linger l_val;
+  socklen_t l_val_len = sizeof(l_val);
+
+  switch (optID) {
+#ifdef TCP_NODELAY
+    case _Jv_TCP_NODELAY_ :
+      if (::getsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, &val, &val_len) != 0)
+        goto error;
+      else return new java::lang::Boolean (val != 0);
+#else
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("TCP_NODELAY not supported")));      
+#endif       
+    break;
+
+    case _Jv_SO_LINGER_ :
+#ifdef SO_LINGER
+      if (::getsockopt (fnum, SOL_SOCKET, SO_LINGER, 
+                        &l_val, &l_val_len) != 0) goto error;    
+      if (l_val.l_onoff)
+        return new java::lang::Integer (l_val.l_linger);
+      else return new java::lang::Boolean (false);
+#else
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("SO_LINGER not supported")));      	
+#endif
+      break;    
+    case _Jv_SO_RCVBUF_ :
+    case _Jv_SO_SNDBUF_ :
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+      int opt;
+      optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+        if (::getsockopt (fnum, SOL_SOCKET, opt, 
+ 	                  &val, &val_len) != 0) goto error;    
+	else return new java::lang::Integer (val);
+#else
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported")));
+#endif    
+      break;
+    case _Jv_SO_BINDADDR_:
+      jbyteArray laddr;
+      if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
+        goto error;
+      if (u.address.sin_family == AF_INET)
+	{
+	  laddr = JvNewByteArray (4);
+	  memcpy (elements (laddr), &u.address.sin_addr, 4);
+	}
+    #ifdef HAVE_INET6
+      else if (u.address.sin_family == AF_INET6)
+	{
+	  laddr = JvNewByteArray (16);
+	  memcpy (elements (laddr), &u.address6.sin6_addr, 16);
+	}
+    #endif
+      else goto error;
+      return new java::net::InetAddress (laddr, NULL);
+      break;
+    case _Jv_IP_MULTICAST_IF_ :
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("IP_MULTICAST_IF: option not implemented")));
+      break;
+    case _Jv_SO_REUSEADDR_ :
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("SO_REUSEADDR: option not implemented")));
+      break;
+    case _Jv_SO_TIMEOUT_ :
+      JvThrow (new java::lang::InternalError (
+        JvNewStringUTF ("SO_TIMEOUT: option not implemented")));
+      break;
+  }
+  error:
+    char msg[100];
+    char* strerr = strerror (errno);
+    sprintf (msg, "SocketImpl.getOption: %.*s", 75, strerr);
+    JvThrow (new java::net::SocketException (JvNewStringUTF (msg)));
 }
package java.net;

public interface SocketOptions 
{
  public static final int IP_MULTICAST_IF = 1;
  public static final int SO_BINDADDR = 2;
  public static final int SO_LINGER = 3;
  public static final int SO_SNDBUF = 4;
  public static final int SO_RCVBUF = 5;
  public static final int SO_REUSEADDR = 6;
  public static final int SO_TIMEOUT = 7;
  public static final int TCP_NODELAY = 8;
  
  public Object getOption(int optID) throws SocketException;
		 
  public void setOption(int optID, Object value) throws SocketException;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]