+2002-08-29 Tom Tromey <tromey@redhat.com>
+
+ * java/net/JarURLConnection.java (getCertificates): New method
+ from Classpath.
+ * java/net/URLClassLoader.java (URLClassLoader): Extends
+ SecureClassLoader.
+ (definePackage): New method from Classpath.
+ (getPermissions): Likewise.
+ (newInstance): Likewise.
+ (findClass): Construct CodeSource for new class (from Classpath).
+ * java/net/SocketImpl.java (shutdownInput, shutdownOutput): New
+ methods.
+ * java/net/URL.java (getUserInfo): New method.
+ (set(String,String,int,String,String,String,String,String)): New
+ method.
+ * java/net/PlainSocketImpl.java (_Jv_SO_KEEPALIVE_): Define.
+ (shutdownInput, shutdownOutput): Declare.
+ * java/net/PlainDatagramSocketImpl.java (_Jv_SO_KEEPALIVE_):
+ Define.
+ * java/net/natPlainSocketImpl.cc (setOption): Handle keepalive.
+ (getOption): Likewise.
+ (shutdownInput): New method.
+ (shutdownOutput): Likewise.
+ * java/net/natPlainDatagramSocketImpl.cc (setOption): Handle
+ keepalive.
+ (getOption): Likewise.
+ * java/net/SocketOptions.java (SO_KEEPALIVE): New constant.
+ * java/net/Socket.java (setKeepAlive): New method.
+ (getKeepAlive): Likewise.
+ (shutdownInput, shutdownOutput): New methods.
+
2002-08-29 Michael Koch <konqueror@gmx.de>
* java/net/DatagramPacket.java: updated to JDK 1.4 API
-/* Copyright (C) 1999, 2000 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2002 Free Software Foundation
This file is part of libgcj.
import java.util.Map;
import java.util.Vector;
import java.util.Hashtable;
+import java.security.cert.Certificate;
/**
* @author Kresten Krab Thorup <krab@gnu.org>
hdrHash.put(key.toLowerCase(), Long.toString(len));
}
+ /**
+ * Returns an array of Certificate objects for the jar file entry specified
+ * by this URL or null if there are none
+ *
+ * @return A Certificate array
+ *
+ * @exception IOException If an error occurs
+ */
+ public Certificate[] getCertificates() throws IOException
+ {
+ return getJarEntry().getCertificates();
+ }
}
// PlainDatagramSocketImpl.java - Implementation of DatagramSocketImpl.
-/* Copyright (C) 1999 Free Software Foundation
+/* Copyright (C) 1999, 2002 Free Software Foundation
This file is part of libgcj.
_Jv_SO_LINGER_ = SocketOptions.SO_LINGER,
_Jv_SO_TIMEOUT_ = SocketOptions.SO_TIMEOUT,
_Jv_SO_SNDBUF_ = SocketOptions.SO_SNDBUF,
- _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF;
+ _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF,
+ _Jv_SO_KEEPALIVE_ = SocketOptions.SO_KEEPALIVE;
int fnum = -1;
_Jv_SO_LINGER_ = SocketOptions.SO_LINGER,
_Jv_SO_TIMEOUT_ = SocketOptions.SO_TIMEOUT,
_Jv_SO_SNDBUF_ = SocketOptions.SO_SNDBUF,
- _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF;
+ _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF,
+ _Jv_SO_KEEPALIVE_ = SocketOptions.SO_KEEPALIVE;
/**
* The OS file handle representing the socket.
public native Object getOption(int optID) throws SocketException;
+ public native void shutdownInput () throws IOException;
+
+ public native void shutdownOutput () throws IOException;
+
protected native void create (boolean stream) throws IOException;
protected void connect (String host, int port) throws IOException
throw new SocketException("Internal Error: Unexpected type");
}
+ /**
+ * This method sets the value for the socket level socket option
+ * SO_KEEPALIVE.
+ *
+ * @param on True if SO_KEEPALIVE should be enabled
+ *
+ * @exception SocketException If an error occurs or Socket is not connected
+ *
+ * @since Java 1.3
+ */
+ public void setKeepAlive (boolean on) throws SocketException
+ {
+ if (impl == null)
+ throw new SocketException("Not connected");
+
+ impl.setOption(SocketOptions.SO_RCVBUF, new Boolean(on));
+ }
+
+ /**
+ * This method returns the value of the socket level socket option
+ * SO_KEEPALIVE.
+ *
+ * @return The setting
+ *
+ * @exception SocketException If an error occurs or Socket is not connected
+ *
+ * @since Java 1.3
+ */
+ public boolean getKeepAlive () throws SocketException
+ {
+ if (impl == null)
+ throw new SocketException("Not connected");
+
+ Object buf = impl.getOption(SocketOptions.SO_RCVBUF);
+
+ if (buf instanceof Boolean)
+ return(((Boolean)buf).booleanValue());
+ else
+ throw new SocketException("Internal Error: Unexpected type");
+ }
+
/**
* Closes the socket.
*
factory = fac;
}
+
+ /**
+ * Closes the input side of the socket stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public void shutdownInput() throws IOException
+ {
+ if (impl != null)
+ impl.shutdownInput();
+ }
+
+ /**
+ * Closes the output side of the socket stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public void shutdownOutput() throws IOException
+ {
+ if (impl != null)
+ impl.shutdownOutput();
+ }
}
* @XXX This redeclaration from SocketOptions is a workaround to a gcj bug.
*/
public abstract Object getOption(int option_id) throws SocketException;
+
+ /**
+ * Shut down the input side of this socket. Subsequent reads will
+ * return end-of-file.
+ *
+ * @exception IOException if an error occurs
+ */
+ public abstract void shutdownInput () throws IOException;
+
+ /**
+ * Shut down the output side of this socket. Subsequent writes will
+ * fail with an IOException.
+ *
+ * @exception IOException if an error occurs
+ */
+ public abstract void shutdownOutput () throws IOException;
}
/* SocketOptions.java -- Implements options for sockets (duh!)
- Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath.
* Static Variables
*/
+/**
+ * Option id for the SO_KEEPALIVE value
+ */
+static final int SO_KEEPALIVE = 0x8;
+
/**
* Option id for the SO_LINGER value
*/
this.handler = setURLStreamHandler(protocol);
if (this.handler == null)
- throw new MalformedURLException("Protocol handler not found: " + protocol);
+ throw new MalformedURLException("Protocol handler not found: "
+ + protocol);
// JDK 1.2 doc for parseURL specifically states that any '#' ref
// is to be excluded by passing the 'limit' as the indexOf the '#'
return ref;
}
+ public String getUserInfo ()
+ {
+ int at = host.indexOf('@');
+ return at < 0 ? null : host.substring(0, at);
+ }
+
public int hashCode()
{
// JCL book says this is computed using (only) the hashcodes of the
hashCode = hashCode(); // Used for serialization.
}
+ /** @since 1.3 */
+ protected void set(String protocol, String host, int port,
+ String authority, String userInfo,
+ String path, String query, String ref)
+ {
+ // TBD: Theoretically, a poorly written StreamHandler could pass an
+ // invalid protocol. It will cause the handler to be set to null
+ // thus overriding a valid handler. Callers of this method should
+ // be aware of this.
+ this.handler = setURLStreamHandler(protocol);
+ this.protocol = protocol;
+ if (userInfo == null)
+ this.host = host;
+ else
+ this.host = userInfo + "@" + host;
+ this.port = port;
+ if (query == null)
+ this.file = path;
+ else
+ this.file = path + "?" + query;
+ this.ref = ref;
+ hashCode = hashCode(); // Used for serialization.
+ }
+
public static synchronized void
setURLStreamHandlerFactory(URLStreamHandlerFactory fac)
{
-/* Copyright (C) 1999, 2000 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2002 Free Software Foundation
This file is part of libgcj.
import java.util.jar.*;
import java.util.Enumeration;
import java.util.Vector;
+import java.security.CodeSource;
+import java.security.SecureClassLoader;
+import java.security.PermissionCollection;
+import java.security.cert.Certificate;
/**
* @since 1.2
*/
-public class URLClassLoader extends ClassLoader
+public class URLClassLoader extends SecureClassLoader
{
// The URLStreamHandlerFactory
URLStreamHandlerFactory factory = null;
try
{
- URL u = getResource (name.replace ('.', '/') + ".class");
+ URL url = getResource (name.replace ('.', '/') + ".class");
- if (u == null)
+ if (url == null)
throw new ClassNotFoundException (name);
- URLConnection connection = u.openConnection ();
+ URLConnection connection = url.openConnection ();
InputStream is = connection.getInputStream ();
int len = connection.getContentLength ();
off += c;
}
- return defineClass (name, data, 0, len);
+ // Now construct the CodeSource (if loaded from a jar file)
+ CodeSource source = null;
+ if (url.getProtocol().equals("jar"))
+ {
+ Certificate[] certificates =
+ ((JarURLConnection) connection).getCertificates();
+ String u = url.toExternalForm ();
+ u = u.substring (4); //skip "jar:"
+ int i = u.indexOf ('!');
+ if (i >= 0)
+ u = u.substring (0, i);
+ url = new URL("jar", "", u);
+
+ source = new CodeSource(url, certificates);
+ }
+ else if (url.getProtocol().equals("file"))
+ {
+ try
+ {
+ String u = url.toExternalForm();
+ // Skip "file:" and then get canonical directory name.
+ File f = new File(u.substring(5));
+ f = f.getCanonicalFile();
+ url = new URL("file", "", f.getParent());
+ source = new CodeSource (url, null);
+ }
+ catch (IOException ignore)
+ {
+ }
+ }
+
+ return defineClass (name, data, 0, len, source);
}
catch (java.io.IOException x)
{
throw new ClassNotFoundException(name);
}
}
-}
+ /**
+ * Defines a Package based on the given name and the supplied manifest
+ * information. The manifest indicates the tile, version and
+ * vendor information of the specification and implementation and wheter the
+ * package is sealed. If the Manifest indicates that the package is sealed
+ * then the Package will be sealed with respect to the supplied URL.
+ *
+ * @exception IllegalArgumentException If this package name already exists
+ * in this class loader
+ * @param name The name of the package
+ * @param manifest The manifest describing the specification,
+ * implementation and sealing details of the package
+ * @param url the code source url to seal the package
+ * @return the defined Package
+ */
+ protected Package definePackage(String name, Manifest manifest, URL url)
+ throws IllegalArgumentException
+ {
+ Attributes attr = manifest.getMainAttributes();
+ String specTitle =
+ attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
+ String specVersion =
+ attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
+ String specVendor =
+ attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
+ String implTitle =
+ attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
+ String implVersion =
+ attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+ String implVendor =
+ attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
+
+ // Look if the Manifest indicates that this package is sealed
+ // XXX - most likely not completely correct!
+ // Shouldn't we also check the sealed attribute of the complete jar?
+ // http://java.sun.com/products/jdk/1.3/docs/guide/extensions/spec.html#bundled
+ // But how do we get that jar manifest here?
+ String sealed = attr.getValue(Attributes.Name.SEALED);
+ if ("false".equals(sealed))
+ {
+ // Make sure that the URL is null so the package is not
+ // sealed.
+ url = null;
+ }
+
+ return definePackage(name, specTitle, specVersion, specVendor,
+ implTitle, implVersion, implVendor, url);
+ }
+
+ /**
+ * Returns the permissions needed to access a particular code source.
+ * These permissions includes those returned by
+ * <CODE>SecureClassLoader.getPermissions</CODE> and the actual permissions
+ * to access the objects referenced by the URL of the code source.
+ * The extra permissions added depend on the protocol and file portion of
+ * the URL in the code source. If the URL has the "file" protocol ends with
+ * a / character then it must be a directory and a file Permission to read
+ * everthing in that directory and all subdirectories is added. If the URL
+ * had the "file" protocol and doesn't end with a / character then it must
+ * be a normal file and a file permission to read that file is added. If the
+ * URL has any other protocol then a socket permission to connect and accept
+ * connections from the host portion of the URL is added.
+ * @param source The codesource that needs the permissions to be accessed
+ * @return the collection of permissions needed to access the code resource
+ * @see SecureClassLoader.getPermissions()
+ */
+ protected PermissionCollection getPermissions(CodeSource source)
+ {
+ // XXX - This implementation does exactly as the Javadoc describes.
+ // But maybe we should/could use URLConnection.getPermissions()?
+
+ // First get the permissions that would normally be granted
+ PermissionCollection permissions = super.getPermissions(source);
+
+ // Now add the any extra permissions depending on the URL location
+ URL url = source.getLocation();
+ String protocol = url.getProtocol();
+ if (protocol.equals("file"))
+ {
+ String file = url.getFile();
+ // If the file end in / it must be an directory
+ if (file.endsWith("/"))
+ {
+ // Grant permission to read everything in that directory and
+ // all subdirectories
+ permissions.add(new FilePermission(file + "-", "read"));
+ }
+ else
+ {
+ // It is a 'normal' file
+ // Grant permission to access that file
+ permissions.add(new FilePermission(file, "read"));
+ }
+ }
+ else
+ {
+ // Grant permission to connect to and accept connections from host
+ String host = url.getHost();
+ permissions.add(new SocketPermission(host, "connect,accept"));
+ }
+
+ return permissions;
+ }
+
+ /**
+ * Creates a new instance of a URLClassLoader that gets classes from the
+ * supplied URLs. This class loader will have as parent the standard
+ * system class loader.
+ * @param urls the initial URLs used to resolve classes and resources
+ */
+ public static URLClassLoader newInstance(URL urls[]) throws
+ SecurityException
+ {
+ return new URLClassLoader(urls);
+ }
+
+ /**
+ * Creates a new instance of a URLClassLoader that gets classes from the
+ * supplied URLs and with the supplied loader as parent class loader.
+ * @param urls the initial URLs used to resolve classes and resources
+ * @param parent the parent class loader
+ */
+ public static URLClassLoader newInstance(URL urls[],
+ ClassLoader parent)
+ throws SecurityException
+ {
+ return new URLClassLoader(urls, parent);
+ }
+}
throw new java::net::SocketException (
JvNewStringUTF ("SO_LINGER not valid for UDP"));
return;
+ case _Jv_SO_KEEPALIVE_ :
+ throw new java::net::SocketException (
+ JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
+ return;
case _Jv_SO_SNDBUF_ :
case _Jv_SO_RCVBUF_ :
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
throw new java::net::SocketException (
JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
break;
-
case _Jv_SO_LINGER_ :
throw new java::net::SocketException (
JvNewStringUTF ("SO_LINGER not valid for UDP"));
break;
+ case _Jv_SO_KEEPALIVE_ :
+ throw new java::net::SocketException (
+ JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
+ break;
case _Jv_SO_RCVBUF_ :
case _Jv_SO_SNDBUF_ :
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
JvNewStringLatin1 ("SocketImpl.close: unimplemented"));
}
+void
+java::net::PlainSocketImpl::shutdownInput (void)
+{
+ throw new SocketException (
+ JvNewStringLatin1 ("SocketImpl.shutdownInput: unimplemented"));
+}
+
+void
+java::net::PlainSocketImpl::shutdownOutput (void)
+{
+ throw new SocketException (
+ JvNewStringLatin1 ("SocketImpl.shutdownOutput: unimplemented"));
+}
+
#else /* DISABLE_JAVA_NET */
union SockAddr
#ifdef TCP_NODELAY
if (::setsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
val_len) != 0)
- goto error;
+ goto error;
#else
throw new java::lang::InternalError (
JvNewStringUTF ("TCP_NODELAY not supported"));
#endif /* TCP_NODELAY */
return;
+
+ case _Jv_SO_KEEPALIVE_ :
+ if (::setsockopt (fnum, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+ val_len) != 0)
+ goto error;
+
case _Jv_SO_LINGER_ :
#ifdef SO_LINGER
struct linger l_val;
JvNewStringUTF ("SO_LINGER not supported"));
#endif
break;
+
+ case _Jv_SO_KEEPALIVE_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ else
+ return new java::lang::Boolean (val != 0);
+
case _Jv_SO_RCVBUF_ :
case _Jv_SO_SNDBUF_ :
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
throw new java::net::SocketException (JvNewStringUTF (strerr));
}
+void
+java::net::PlainSocketImpl::shutdownInput (void)
+{
+ if (::shutdown (fnum, 0))
+ throw new SocketException (JvNewStringUTF (strerror (errno)));
+}
+
+void
+java::net::PlainSocketImpl::shutdownOutput (void)
+{
+ if (::shutdown (fnum, 1))
+ throw new SocketException (JvNewStringUTF (strerror (errno)));
+}
+
#endif /* DISABLE_JAVA_NET */