summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron M. Renn <arenn@urbanophile.com>1998-05-18 00:34:12 +0000
committerAaron M. Renn <arenn@urbanophile.com>1998-05-18 00:34:12 +0000
commitcef12ba87faabdb23fc796df9046ddf61247e325 (patch)
treef19569ad75e9695f2448093caeed508768f9a5cb
parente5cd4c332de77192e9beb4b0533a2e6ffe0e0cd1 (diff)
downloadclasspath-cef12ba87faabdb23fc796df9046ddf61247e325.tar.gz
Initial Checkin
-rw-r--r--gnu/Makefile.am4
-rw-r--r--gnu/java/Makefile.am4
-rw-r--r--gnu/java/net/Makefile.am4
-rw-r--r--gnu/java/net/content/Makefile.am4
-rw-r--r--gnu/java/net/content/text/ChangeLog8
-rw-r--r--gnu/java/net/content/text/Makefile.am6
-rw-r--r--gnu/java/net/content/text/plain.java70
-rw-r--r--gnu/java/net/http/ChangeLog18
-rw-r--r--gnu/java/net/http/Handler.java77
-rw-r--r--gnu/java/net/http/HttpURLConnection.java321
-rw-r--r--gnu/java/net/http/Makefile.am6
-rw-r--r--gnu/java/net/http/TODO18
-rw-r--r--java/Makefile.am4
-rw-r--r--java/net/ContentHandler.java74
-rw-r--r--java/net/ContentHandlerFactory.java45
-rw-r--r--java/net/DatagramPacket.java240
-rw-r--r--java/net/DatagramSocket.java230
-rw-r--r--java/net/DatagramSocketImpl.java217
-rw-r--r--java/net/FileNameMap.java43
-rw-r--r--java/net/HttpURLConnection.java433
-rw-r--r--java/net/InetAddress.java661
-rw-r--r--java/net/JarURLConnection.java237
-rw-r--r--java/net/Makefile.am23
-rw-r--r--java/net/MalformedURLException.java61
-rw-r--r--java/net/MimeTypeMapper.java216
-rw-r--r--java/net/MulticastSocket.java197
-rw-r--r--java/net/NetPermission.java72
-rw-r--r--java/net/NoRouteToHostException.java61
-rw-r--r--java/net/PasswordAuthentication.java99
-rw-r--r--java/net/PlainDatagramSocketImpl.java250
-rw-r--r--java/net/PlainSocketImpl.java285
-rw-r--r--java/net/ProtocolException.java62
-rw-r--r--java/net/STATUS48
-rw-r--r--java/net/ServerSocket.java324
-rw-r--r--java/net/Socket.java591
-rw-r--r--java/net/SocketException.java62
-rw-r--r--java/net/SocketImpl.java295
-rw-r--r--java/net/SocketImplFactory.java40
-rw-r--r--java/net/SocketInputStream.java189
-rw-r--r--java/net/SocketOptions.java108
-rw-r--r--java/net/SocketOutputStream.java148
-rw-r--r--java/net/SocketPermission.java380
-rw-r--r--java/net/TODO26
-rw-r--r--java/net/URL.java690
-rw-r--r--java/net/URLConnection.java912
-rw-r--r--java/net/URLEncoder.java110
-rw-r--r--java/net/URLStreamHandler.java251
-rw-r--r--java/net/URLStreamHandlerFactory.java44
-rw-r--r--java/net/UnknownHostException.java63
-rw-r--r--java/net/UnknownServiceException.java63
-rw-r--r--native/Makefile.am8
-rw-r--r--native/config.h1
-rw-r--r--native/config.h.in0
-rw-r--r--native/java.net/ChangeLog43
-rw-r--r--native/java.net/InetAddress.c190
-rw-r--r--native/java.net/Makefile.am39
-rw-r--r--native/java.net/PlainDatagramSocketImpl.c258
-rw-r--r--native/java.net/PlainSocketImpl.c154
-rw-r--r--native/java.net/javanet.c1012
-rw-r--r--native/java.net/javanet.h83
-rw-r--r--test/Makefile.am4
-rw-r--r--test/java.net/ClientDatagram.java112
-rw-r--r--test/java.net/ClientSocket.java189
-rw-r--r--test/java.net/Makefile.am9
-rw-r--r--test/java.net/MulticastClient.java65
-rw-r--r--test/java.net/MulticastServer.java57
-rw-r--r--test/java.net/ServerDatagram.java52
-rw-r--r--test/java.net/ServerSocketTest.java53
-rw-r--r--test/java.net/SubSocket.java6
-rw-r--r--test/java.net/TestNameLookups.java103
-rw-r--r--test/java.net/URLTest.java150
-rwxr-xr-xtest/java.net/runtest32
72 files changed, 11014 insertions, 0 deletions
diff --git a/gnu/Makefile.am b/gnu/Makefile.am
new file mode 100644
index 000000000..4163db7d3
--- /dev/null
+++ b/gnu/Makefile.am
@@ -0,0 +1,4 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+SUBDIRS = java
+
diff --git a/gnu/java/Makefile.am b/gnu/java/Makefile.am
new file mode 100644
index 000000000..656bb40c9
--- /dev/null
+++ b/gnu/java/Makefile.am
@@ -0,0 +1,4 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+SUBDIRS = net
+
diff --git a/gnu/java/net/Makefile.am b/gnu/java/net/Makefile.am
new file mode 100644
index 000000000..35d55a582
--- /dev/null
+++ b/gnu/java/net/Makefile.am
@@ -0,0 +1,4 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+SUBDIRS = content http
+
diff --git a/gnu/java/net/content/Makefile.am b/gnu/java/net/content/Makefile.am
new file mode 100644
index 000000000..174dae80f
--- /dev/null
+++ b/gnu/java/net/content/Makefile.am
@@ -0,0 +1,4 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+SUBDIRS = text
+
diff --git a/gnu/java/net/content/text/ChangeLog b/gnu/java/net/content/text/ChangeLog
new file mode 100644
index 000000000..fe92bbc0b
--- /dev/null
+++ b/gnu/java/net/content/text/ChangeLog
@@ -0,0 +1,8 @@
+Sat May 16 15:15:10 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * plain.java: Changed package to gnu.*
+
+Sun May 3 21:04:11 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * plain.java: Wrote this class
+
diff --git a/gnu/java/net/content/text/Makefile.am b/gnu/java/net/content/text/Makefile.am
new file mode 100644
index 000000000..bb8a15e23
--- /dev/null
+++ b/gnu/java/net/content/text/Makefile.am
@@ -0,0 +1,6 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+textdir = $(datadir)/gnu/java/net/content/text
+
+text_JAVA = plain.java
+
diff --git a/gnu/java/net/content/text/plain.java b/gnu/java/net/content/text/plain.java
new file mode 100644
index 000000000..405ad1a4a
--- /dev/null
+++ b/gnu/java/net/content/text/plain.java
@@ -0,0 +1,70 @@
+/*************************************************************************
+/* plain.java -- Content Handler for text/plain type
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package gnu.java.net.content.text;
+
+import java.net.ContentHandler;
+import java.net.URLConnection;
+import java.io.IOException;
+
+/**
+ * This class is the ContentHandler for the text/plain MIME type. It
+ * simply returns an InputStream object of the text being read.
+ *
+ * @version 0.1
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class plain extends ContentHandler
+{
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Default do nothing constructor
+ */
+public
+plain()
+{
+ ;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an InputStream as the content for this object
+ *
+ * @param url_con The URLConnection to get the content of
+ *
+ * @return An InputStream for that connection
+ *
+ * @exception IOException If an error occurs
+ */
+public Object
+getContent(URLConnection url_con) throws IOException
+{
+ return(url_con.getInputStream());
+}
+
+} // class plain
+
diff --git a/gnu/java/net/http/ChangeLog b/gnu/java/net/http/ChangeLog
new file mode 100644
index 000000000..44c1503f1
--- /dev/null
+++ b/gnu/java/net/http/ChangeLog
@@ -0,0 +1,18 @@
+Sat May 16 15:13:44 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * HttpURLConnection.java: Switched package to gnu.*
+
+ * Handler.java: Switched package to gnu.*
+
+Sat Apr 25 16:44:30 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * HttpURLConnection.java: Finished off this class
+
+
+Fri Apr 24 18:23:58 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * Handler.java: Wrote this class.
+
+ * HttpURLConnection.java: Wrote an initial cut at this class with
+ all methods stubbed out
+
diff --git a/gnu/java/net/http/Handler.java b/gnu/java/net/http/Handler.java
new file mode 100644
index 000000000..e3d9b2ed5
--- /dev/null
+++ b/gnu/java/net/http/Handler.java
@@ -0,0 +1,77 @@
+/*************************************************************************
+/* Handler.java -- HTTP protocol handler for java.net
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package gnu.java.net.http;
+
+import java.net.URL;
+import java.net.URLStreamHandler;
+import java.net.URLConnection;
+import java.io.IOException;
+
+/**
+ * This is the protocol handler for the HTTP protocol. It implements
+ * the abstract openConnection() method from URLStreamHandler by returning
+ * a new HttpURLConnection object (from this package). All other
+ * methods are inherited
+ *
+ * @version 0.1
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class Handler extends URLStreamHandler
+{
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * A do nothing constructor
+ */
+public
+Handler()
+{
+ ;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * This method returs a new HttpURLConnection for the specified URL
+ *
+ * @param url The URL to return a connection for
+ *
+ * @return The URLConnection
+ *
+ * @exception IOException If an error occurs
+ */
+protected URLConnection
+openConnection(URL url) throws IOException
+{
+ return(new gnu.java.net.http.HttpURLConnection(url));
+}
+
+} // class Handler
+
diff --git a/gnu/java/net/http/HttpURLConnection.java b/gnu/java/net/http/HttpURLConnection.java
new file mode 100644
index 000000000..33212c46e
--- /dev/null
+++ b/gnu/java/net/http/HttpURLConnection.java
@@ -0,0 +1,321 @@
+/*************************************************************************
+/* HttpURLConnection.java -- URLConnection class for HTTP protocol
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package gnu.java.net.http;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.Socket;
+import java.net.ProtocolException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.IOException;
+
+/**
+ * This subclass of java.net.URLConnection models a URLConnection via
+ * the HTTP protocol.
+ *
+ * @version 0.1
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class HttpURLConnection extends java.net.HttpURLConnection
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The socket we are connected to
+ */
+protected Socket socket;
+
+/**
+ * The InputStream for this connection
+ */
+protected InputStream in_stream;
+
+/**
+ * The OutputStream for this connection
+ */
+protected OutputStream out_stream;
+
+/**
+ * The PrintWriter for this connection (used internally)
+ */
+protected PrintWriter out_writer;
+
+/**
+ * The InputStreamReader for this connection (used internally)
+ */
+protected InputStreamReader in_reader;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Calls superclass constructor to initialize
+ */
+protected
+HttpURLConnection(URL url)
+{
+ super(url);
+
+ /* Set up some variables */
+ doOutput = false;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * Reads a line of text from the InputStream
+ */
+private String
+readLine() throws IOException
+{
+ StringBuffer sb = new StringBuffer("");
+
+ byte[] buf = new byte[1];
+ for (;;)
+ {
+ int read = in_stream.read(buf, 0, 1);
+ if (read == -1)
+ throw new IOException("Premature end of input");
+
+ if (buf[0] == '\r')
+ continue;
+ if (buf[0] == '\n')
+ break;
+ sb.append((char)buf[0]);
+ }
+ return(sb.toString());
+}
+
+/*************************************************************************/
+
+/**
+ * Connects to the remote host, sends the request, and parses the reply
+ * code and header information returned
+ */
+public void
+connect() throws IOException
+{
+ // Connect up
+ if (url.getPort() == -1)
+ socket = new Socket(url.getHost(), 80);
+ else
+ socket = new Socket(url.getHost(), url.getPort());
+
+ out_stream = socket.getOutputStream();
+ in_stream = socket.getInputStream();
+
+ in_reader = new InputStreamReader(in_stream);
+ out_writer = new PrintWriter(new OutputStreamWriter(out_stream));
+
+ // Send the request
+ out_writer.print(getRequestMethod() + " " + getURL().getFile() +
+ " HTTP/1.1\r\n");
+
+ String propval = getRequestProperty("host");
+ if (propval == null)
+ out_writer.print("Host: " + getURL().getHost() + "\r\n");
+ else
+ out_writer.print("Host: " + propval + "\r\n");
+ out_writer.print("Connection: close" + "\r\n");
+
+ propval = getRequestProperty("user-agent");
+ if (propval == null)
+ out_writer.print("User-Agent: jcl/0.0\r\n");
+ else
+ out_writer.print("User-Agent: " + propval + "\r\n");
+
+ propval = getRequestProperty("accept");
+ if (propval == null)
+ out_writer.print("Accept: */*\r\n");
+ else
+ out_writer.print("Accept: " + propval + "\r\n");
+
+ out_writer.print("\r\n");
+ out_writer.flush();
+
+ // Parse the reply
+ String line = readLine();
+ String saveline = line;
+
+ int idx = line.indexOf(" " );
+ if ((idx == -1) || (line.length() < (idx + 6)))
+ throw new IOException("Server reply was unparseable: " + saveline);
+
+ line = line.substring(idx + 1);
+ String code = line.substring(0, 3);
+ try
+ {
+ responseCode = Integer.parseInt(code);
+ }
+ catch (NumberFormatException e)
+ {
+ throw new IOException("Server reply was unparseable: " + saveline);
+ }
+ responseMessage = line.substring(4);
+
+ // Now read the header lines
+ String key = null, value = null;
+ for (;;)
+ {
+ line = readLine();
+ if (line.equals(""))
+ break;
+
+ // Check for folded lines
+ if (line.startsWith(" ") || line.startsWith("\t"))
+ {
+ // Trim off leading space
+ do
+ {
+ if (line.length() == 1)
+ throw new IOException("Server header lines were unparseable: " +
+ line);
+
+ line = line.substring(1);
+ }
+ while (line.startsWith(" ") || line.startsWith("\t"));
+
+ value = value + " " + line;
+ }
+ else
+ {
+ if (key != null)
+ {
+ headerKeys.addElement(key.toLowerCase());
+ headerValues.addElement(value);
+ key = null;
+ value = null;
+ }
+
+ // Parse out key and value
+ idx = line.indexOf(":");
+ if ((idx == -1) || (line.length() < (idx + 2)))
+ throw new IOException("Server header lines were unparseable: " + line);
+
+ key = line.substring(0, idx);
+ value = line.substring(idx + 1);
+
+ // Trim off leading space
+ while (value.startsWith(" ") || value.startsWith("\t"))
+ {
+ if (value.length() == 1)
+ throw new IOException("Server header lines were unparseable: " +
+ line);
+
+ value = value.substring(1);
+ }
+ }
+ }
+ if (key != null)
+ {
+ headerKeys.addElement(key.toLowerCase());
+ headerValues.addElement(value);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Disconnects from the remote server
+ */
+public void
+disconnect()
+{
+ try
+ {
+ socket.close();
+ }
+ catch(IOException e) { ; }
+}
+
+/*************************************************************************/
+
+/**
+ * Overrides java.net.HttpURLConnection.setRequestMethod() in order to
+ * restrict the available methods to only those we support.
+ *
+ * @param method The RequestMethod to use
+ *
+ * @exception ProtocolException If the specified method is not valid
+ */
+public void
+setRequestMethod(String method) throws ProtocolException
+{
+ method = method.toUpperCase();
+ if (method.equals("GET") || method.equals("HEAD"))
+ super.setRequestMethod(method);
+ else
+ throw new ProtocolException("Unsupported or unknown request method " +
+ method);
+}
+
+/*************************************************************************/
+
+/**
+ * Return a boolean indicating whether or not this connection is
+ * going through a proxy
+ *
+ * @return true if using a proxy, false otherwise
+ */
+public boolean
+usingProxy()
+{
+ return(false);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an InputStream for reading from this connection. This stream
+ * will be "queued up" for reading just the contents of the requested file.
+ * Overrides URLConnection.getInputStream()
+ *
+ * @return An InputStream for this connection.
+ *
+ * @exception IOException If an error occurs
+ */
+public InputStream
+getInputStream() throws IOException
+{
+ if (!connected)
+ connect();
+
+ return(in_stream);
+}
+
+} // class HttpURLConnection
+
diff --git a/gnu/java/net/http/Makefile.am b/gnu/java/net/http/Makefile.am
new file mode 100644
index 000000000..243e6dd38
--- /dev/null
+++ b/gnu/java/net/http/Makefile.am
@@ -0,0 +1,6 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+httpdir = $(datadir)/gnu/java/net/http
+
+http_JAVA = HttpURLConnection.java Handler.java
+
diff --git a/gnu/java/net/http/TODO b/gnu/java/net/http/TODO
new file mode 100644
index 000000000..f4fc5c660
--- /dev/null
+++ b/gnu/java/net/http/TODO
@@ -0,0 +1,18 @@
+-- Base protocol
+
+-- Proxy support
+
+-- Caching
+
+-- If modified since support
+
+-- Connect, getInputStream(), getOutputStream, disconnect()
+
+-- Header parsing
+
+-- GET method implementation only
+
+-- Request parameter handling
+
+-- Basically everything beyond simple fetching
+
diff --git a/java/Makefile.am b/java/Makefile.am
new file mode 100644
index 000000000..656bb40c9
--- /dev/null
+++ b/java/Makefile.am
@@ -0,0 +1,4 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+SUBDIRS = net
+
diff --git a/java/net/ContentHandler.java b/java/net/ContentHandler.java
new file mode 100644
index 000000000..93aca22ba
--- /dev/null
+++ b/java/net/ContentHandler.java
@@ -0,0 +1,74 @@
+/*************************************************************************
+/* ContentHandler.java -- Abstract class for handling content from URL's
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * This is an abstract class that is the superclass for classes that read
+ * objects from URL's. Calling the getContent() method in the URL class
+ * or the URLConnection class will cause an instance of a subclass of
+ * ContentHandler to be created for the MIME type of the object being
+ * downloaded from the URL. Thus, this class is seldom needed by
+ * applications/applets directly, but only indirectly through methods in
+ * other classes.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract class ContentHandler
+{
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Do nothing constructor
+ */
+public
+ContentHandler()
+{
+ ;
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads from the InputStream of the passed in URL connection
+ * and uses the data downloaded to create an Object represening the
+ * content. For example, if the URL is pointing to a GIF file, this
+ * method might return an Image object. This method should be overridden
+ * by subclasses.
+ *
+ * @param urlcon A URLConnection object to read data from
+ *
+ * @return An object representing the data read
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract synchronized Object
+getContent(URLConnection urlcon) throws IOException;
+
+} // class ContentHandler
+
diff --git a/java/net/ContentHandlerFactory.java b/java/net/ContentHandlerFactory.java
new file mode 100644
index 000000000..65b8e47ed
--- /dev/null
+++ b/java/net/ContentHandlerFactory.java
@@ -0,0 +1,45 @@
+/*************************************************************************
+/* ContentHandlerFactory.java -- Interface for creating content handlers
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This interface maps MIME types to ContentHandler objects. It consists
+ * of one method that, when passed a MIME type, returns a handler for that
+ * type.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public interface ContentHandlerFactory
+{
+/**
+ * This method is passed a MIME type as a string and is responsible for
+ * returning the appropriate ContentType object.
+ *
+ * @param mime_type The MIME type to map to a ContentHandler
+ *
+ * @return The ContentHandler for the passed in MIME type
+ */
+public abstract ContentHandler
+createContentHandler(String mime_type);
+
+} // interface ContentHandlerFactory
+
diff --git a/java/net/DatagramPacket.java b/java/net/DatagramPacket.java
new file mode 100644
index 000000000..66c8dfe1d
--- /dev/null
+++ b/java/net/DatagramPacket.java
@@ -0,0 +1,240 @@
+/*************************************************************************
+/* DatagramPacket.java -- Class to model a packet to be sent via UDP
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This class models a packet of data that is to be sent across the network
+ * using a connectionless protocol such as UDP. It contains the data
+ * to be send, as well as the destination address and port. Note that
+ * datagram packets can arrive in any order and are not guaranteed to be
+ * delivered at all.
+ * <p>
+ * This class can also be used for receiving data from the network.
+ * <p>
+ * Note that for all method below where the buffer length passed by the
+ * caller cannot exceed the actually length of the byte array passed as
+ * the buffer, if this condition is not true, then the method silently
+ * reduces the length value to maximum allowable value.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public final class DatagramPacket
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The data buffer to send
+ */
+protected byte[] buf;
+
+/**
+ * The length of the data buffer to send
+ */
+protected int len;
+
+/**
+ * The address to which the packet should be sent or from which it
+ * was received
+ */
+protected InetAddress addr;
+
+/**
+ * The port to which the packet should be sent or from which it was
+ * was received.
+ */
+protected int port;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Creates a DatagramPacket for receiving packets from the network
+ *
+ * @param buf A buffer for storing the returned packet data
+ * @param len The length of the buffer (must be <= buf.length)
+ */
+public
+DatagramPacket(byte[] buf, int len)
+{
+ // Hmm, what should we do if len > buf.length? I say silently reduce len
+ if (buf == null)
+ len = 0;
+ else if (len > buf.length)
+ len = buf.length;
+
+ this.buf = buf;
+ this.len = len;
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a DatagramPacket for transmitting packets across the network.
+ *
+ * @param buf A buffer containing the data to send
+ * @param len The length of the buffer (must be <= buf.length)
+ * @param addr The address to send to
+ * @param port The port to send to
+ */
+public
+DatagramPacket(byte[] buf, int len, InetAddress addr, int port)
+{
+ this(buf, len);
+
+ this.addr = addr;
+ this.port = port;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * Returns the address that this packet is being sent to or, if it was used
+ * to receive a packet, the address that is was received from. If the
+ * constructor that doesn not take an address was used to create this object
+ * and no packet was actually read into this object, then this method
+ * returns null
+ *
+ * @return The address for this packet
+ */
+public InetAddress
+getAddress()
+{
+ return(addr);
+}
+
+/*************************************************************************/
+
+/**
+ * This sets the address to which the data packet will be transmitted.
+ *
+ * @param addr The destination address
+ */
+public synchronized void
+setAddress(InetAddress addr)
+{
+ this.addr = addr;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the port number this packet is being sent to or, if it was used
+ * to receive a packet, the port that it was received from. If the
+ * constructor that doesn not take an address was used to create this object
+ * and no packet was actually read into this object, then this method
+ * will return 0.
+ *
+ * @return The port number for this packet
+ */
+public int
+getPort()
+{
+ return(port);
+}
+
+/*************************************************************************/
+
+/**
+ * This sets the port to which the data packet will be transmitted.
+ *
+ * @param port The destination port
+ */
+public synchronized void
+setPort(int port)
+{
+ this.port = port;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the data buffer for this packet
+ *
+ * @return This packet's data buffer
+ */
+public byte[]
+getData()
+{
+ return(buf);
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the data buffer for this packet.
+ *
+ * @return The new buffer for this packet
+ */
+public synchronized void
+setData(byte[] buf)
+{
+ this.buf = buf;
+
+ if (buf == null)
+ {
+ this.buf = null;
+ len = 0;
+ }
+ else if (len > buf.length)
+ len = buf.length;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the length of the data in the buffer
+ *
+ * @return The length of the data
+ */
+public int
+getLength()
+{
+ return(len);
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the length of the data in the buffer.
+ *
+ * @param len The new length. (Where len <= buf.length)
+ */
+public synchronized void
+setLength(int len)
+{
+ this.len = len;
+}
+
+} // class DatagramPacket
+
diff --git a/java/net/DatagramSocket.java b/java/net/DatagramSocket.java
new file mode 100644
index 000000000..3fef08592
--- /dev/null
+++ b/java/net/DatagramSocket.java
@@ -0,0 +1,230 @@
+/*************************************************************************
+/* DatagramSocket.java -- A class to model UDP sockets
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * This class models a connectionless datagram socket that sends
+ * individual packets of data across the network. In the TCP/IP world,
+ * this means UDP. Datagram packets do not have guaranteed delivery,
+ * or any guarantee about the order the data will be received on the
+ * remote host.
+ * <p>
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class DatagramSocket
+{
+
+/*************************************************************************/
+
+/**
+ * Instance Variables
+ */
+
+/**
+ * This is the implementation object used by this socket.
+ */
+protected DatagramSocketImpl impl;
+
+/**
+ * This is the address we are bound to
+ */
+protected InetAddress local_addr;
+
+/*************************************************************************/
+
+/**
+ * Constructors
+ */
+
+/**
+ * Create a DatagramSocket that binds to a random port and every
+ * address on the local machine.
+ *
+ * @exception SocketException If an error occurs
+ */
+public
+DatagramSocket() throws SocketException
+{
+ this(0, null);
+}
+
+/*************************************************************************/
+
+/**
+ * Create a DatagramSocket that binds to the specified port and every
+ * address on the local machine
+ *
+ * @param port The local port number to bind to
+ *
+ * @exception SocketException If an error occurs
+ */
+public
+DatagramSocket(int port) throws SocketException
+{
+ this(port, null);
+}
+
+/*************************************************************************/
+
+/**
+ * Create a DatagramSocket that binds to the specified local port and
+ * address
+ *
+ * @param port The local port number to bind to
+ * @param addr The local address to bind to
+ *
+ * @exception SocketException If an error occurs
+ */
+public
+DatagramSocket(int port, InetAddress addr) throws SocketException
+{
+ // Why is there no factory for this?
+ impl = new PlainDatagramSocketImpl();
+
+ impl.create();
+
+ try
+ {
+ if (addr == null)
+ addr = InetAddress.getInaddrAny();
+
+ impl.localPort = port;
+ this.local_addr = addr;
+
+ impl.bind(port, addr);
+
+ local_addr = addr;
+ }
+ catch (UnknownHostException e)
+ {
+ throw new SocketException(e.toString());
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Closes this socket.
+ */
+public synchronized void
+close()
+{
+ impl.close();
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the local address this socket is bound to
+ */
+public InetAddress
+getLocalAddress()
+{
+ return(local_addr);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the local port this socket is bound to
+ */
+public int
+getLocalPort()
+{
+ return(impl.getLocalPort());
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the socket's SO_TIMEOUT setting. If this method
+ * returns 0 then SO_TIMEOUT is disabled.
+ *
+ * @exception SocketException If an error occurs
+ */
+public synchronized int
+getSoTimeout() throws SocketException
+{
+ Object obj = impl.getOption(SocketOptions.SO_TIMEOUT);
+
+ if (obj instanceof Integer)
+ return(((Integer)obj).intValue());
+ else
+ throw new SocketException("Internal Error");
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the value of the socket's SO_TIMEOUT value. A value of 0 will
+ * disable SO_TIMEOUT. Any other value is the number of milliseconds
+ * a socket read/write will block before timing out.
+ *
+ * @param timeout The new SO_TIMEOUT value
+ *
+ * @exception SocketException If an error occurs
+ */
+public synchronized void
+setSoTimeout(int timeout) throws SocketException
+{
+ impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+}
+
+/*************************************************************************/
+
+/**
+ * Reads a datagram packet from the socket. Note that this method
+ * will block until a packet is received from the network. On return,
+ * the passed in DatagramPacket is populated with the data received
+ * and all the other information about the packet.
+ *
+ * @param packet A DatagramPacket for storing the data
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+receive(DatagramPacket packet) throws IOException
+{
+ impl.receive(packet);
+}
+
+/*************************************************************************/
+
+/**
+ * Sends the specified packet. The host and port to which the packet
+ * are to be sent should be set inside the packet.
+ *
+ * @param packet The packet of data to send
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+send(DatagramPacket packet) throws IOException
+{
+ impl.send(packet);
+}
+
+} // class DatagramSocket
+
diff --git a/java/net/DatagramSocketImpl.java b/java/net/DatagramSocketImpl.java
new file mode 100644
index 000000000..5120d64a7
--- /dev/null
+++ b/java/net/DatagramSocketImpl.java
@@ -0,0 +1,217 @@
+/*************************************************************************
+/* DatagramSocketImpl.java -- Abstract class for UDP socket implementations
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/**
+ * This abstract class models a datagram socket implementation. An
+ * actual implementation class would implement these methods, probably
+ * via redirecting them to native code.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract class DatagramSocketImpl implements SocketOptions
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The FileDescriptor object for this object. *** I would really like to know
+ * how to create one of these. ******
+ */
+protected FileDescriptor fd;
+
+/**
+ * The local port to which this socket is bound
+ */
+protected int localPort;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Do nothing constructor
+ */
+public
+DatagramSocketImpl()
+{
+ ;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * This method binds the socket to the specified local port and address.
+ *
+ * @param port The port number to bind to
+ * @param addr The address to bind to
+ *
+ * @exception SocketException If an error occurs
+ */
+protected abstract synchronized void
+bind(int port, InetAddress addr) throws SocketException;
+
+/*************************************************************************/
+
+/**
+ * This methods closes the socket
+ */
+protected abstract synchronized void
+close();
+
+/*************************************************************************/
+
+/**
+ * Creates a new datagram socket.
+ *
+ * @exception SocketException If an error occurs
+ */
+protected abstract synchronized void
+create() throws SocketException;
+
+/*************************************************************************/
+
+/**
+ * Returns the FileDescriptor for this socket
+ */
+protected FileDescriptor
+getFileDescriptor()
+{
+ return(fd);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the local port this socket is bound to
+ */
+protected int
+getLocalPort()
+{
+ return(localPort);
+}
+
+/*************************************************************************/
+
+/**
+ * This method returns the current Time to Live (TTL) setting on this
+ * socket.
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized byte
+getTTL() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Sets the Time to Live (TTL) setting on this socket to the specified
+ * value.
+ *
+ * @param ttl The new Time to Live value
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+setTTL(byte ttl) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Causes this socket to join the specified multicast group
+ *
+ * @param addr The multicast address to join with
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+join(InetAddress addr) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Causes the socket to leave the specified multicast group.
+ *
+ * @param addr The multicast address to leave
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+leave(InetAddress addr) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Takes a peek at the next packet received in order to retrieve the
+ * address of the sender
+ *
+ * @param ********** Wish I knew what this was for ************
+ *
+ * @return ******* Wish I knew ************
+ *
+ * @exception If an error occurs
+ */
+protected abstract synchronized int
+peek(InetAddress addr) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Receives a packet of data from the network Will block until a packet
+ * arrives. The packet info in populated into the passed in
+ * DatagramPacket object.
+ *
+ * @param packet A place to store the incoming packet.
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+receive(DatagramPacket packet) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Transmits the specified packet of data to the network. The destination
+ * host and port should be encoded in the packet.
+ *
+ * @param packet The packet to send
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+send(DatagramPacket packet) throws IOException;
+
+} // class DatagramSocketImpl
+
diff --git a/java/net/FileNameMap.java b/java/net/FileNameMap.java
new file mode 100644
index 000000000..278c4b625
--- /dev/null
+++ b/java/net/FileNameMap.java
@@ -0,0 +1,43 @@
+/*************************************************************************
+/* FileNameMap.java -- Maps filenames to MIME types
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This interface has one method which, when passed a filename, returns
+ * the MIME type associated with that filename.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public interface FileNameMap
+{
+/**
+ * This method is passed a filename and is responsible for determining
+ * the appropriate MIME type for that file.
+ *
+ * @param filename The name of the file to generate a MIME type for.
+ *
+ * @return The MIME type for the filename passed in.
+ */
+public abstract String
+getContentTypeFor(String filename);
+
+} // interface FileNameMap
diff --git a/java/net/HttpURLConnection.java b/java/net/HttpURLConnection.java
new file mode 100644
index 000000000..a2ea25fa1
--- /dev/null
+++ b/java/net/HttpURLConnection.java
@@ -0,0 +1,433 @@
+/*************************************************************************
+/* HttpURLConnection.java -- HTTP connection to web server
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * This class provides a common abstract implementation for those
+ * URL connection classes that will connect using the HTTP protocol.
+ * In addition to the functionality provided by the URLConnection
+ * class, it defines constants for HTTP return code values and
+ * methods for setting the HTTP request method and determining whether
+ * or not to follow redirects.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract class HttpURLConnection extends URLConnection
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
+ */
+
+// HTTP return codes
+
+/**
+ * Indicates that the client may continue with its request. This value
+ * is specified as part of RFC 2068 but was not included in Sun's JDK, so
+ * beware of using this value
+ */
+public static final int HTTP_CONTINUE = 100;
+
+/**
+ * Indicates that the server received and is willing to comply with a
+ * request to switch protocols initiated by the client. This value is
+ * specified as part of RFC 2068 but was not included in Sun's JDK as of
+ * release 1.2, so beware of using this value.
+ */
+public static final int HTTP_SWITCHING_PROTOCOLS = 101;
+
+/**
+ * Indicates the request succeeded
+ */
+public static final int HTTP_OK = 200;
+
+/**
+ * The requested resource has been created.
+ */
+public static final int HTTP_CREATED = 201;
+
+/**
+ * The request has been accepted for processing but has not completed.
+ * There is no guarantee that the requested action will actually ever
+ * be completed succesfully, but everything is ok so far.
+ */
+public static final int HTTP_ACCEPTED = 202;
+
+/**
+ * The meta-information returned in the header is not the actual data
+ * from the original server, but may be from a local or other copy.
+ * Normally this still indicates a successful completion.
+ */
+public static final int HTTP_NOT_AUTHORITATIVE = 203;
+
+/**
+ * The server performed the request, but there is no data to send
+ * back. This indicates that the user's display should not be changed.
+ */
+public static final int HTTP_NO_CONTENT = 204;
+
+/**
+ * The server performed the request, but there is no data to sent back,
+ * however, the user's display should be "reset" to clear out any form
+ * fields entered.
+ */
+public static final int HTTP_RESET = 205;
+
+/**
+ * The server completed the partial GET request for the resource.
+ */
+public static final int HTTP_PARTIAL = 206;
+
+/**
+ * There is a list of choices available for the requested resource
+ */
+public static final int HTTP_MULT_CHOICE = 300;
+
+/**
+ * The resource has been permanently moved to a new location.
+ */
+public static final int HTTP_MOVED_PERM = 301;
+
+/**
+ * The resource requested has been temporarily moved to a new location.
+ */
+public static final int HTTP_MOVED_TEMP = 302;
+
+/**
+ * The response to the request issued is available at another location
+ */
+public static final int HTTP_SEE_OTHER = 303;
+
+/**
+ * The document has not been modified since the criteria specified in
+ * a conditional GET
+ */
+public static final int HTTP_NOT_MODIFIED = 304;
+
+/**
+ * The requested resource needs to be accessed through a proxy.
+ */
+public static final int HTTP_USE_PROXY = 305;
+
+/**
+ * The request was misformed or could not be understood.
+ */
+public static final int HTTP_BAD_REQUEST = 400;
+
+/**
+ * The request made requires user authorization. Try again with
+ * a correct authentication header.
+ */
+public static final int HTTP_UNAUTHORIZED = 401;
+
+/**
+ * Code reserved for future use - I hope way in the future
+ */
+public static final int HTTP_PAYMENT_REQUIRED = 402;
+
+/**
+ * There is no permission to access the requested resource
+ */
+public static final int HTTP_FORBIDDEN = 403;
+
+/**
+ * The requested resource was not found
+ */
+public static final int HTTP_NOT_FOUND = 404;
+
+/**
+ * The specified request method is not allowed for this resource
+ */
+public static final int HTTP_BAD_METHOD = 405;
+
+/**
+ * Based on the input headers sent, the resource returned in response
+ * to the request would not be acceptable to the client.
+ */
+public static final int HTTP_NOT_ACCEPTABLE = 406;
+
+/**
+ * The client must authenticate with a proxy prior to attempting this
+ * request.
+ */
+public static final int HTTP_PROXY_AUTH = 407;
+
+/**
+ * The request timed out.
+ */
+public static final int HTTP_CLIENT_TIMEOUT = 408;
+
+/**
+ * There is a conflict between the current state of the resource and the
+ * requested action.
+ */
+public static final int HTTP_CONFLICT = 409;
+
+/**
+ * The requested resource is no longer available. This ususally indicates
+ * a permanent condition.
+ */
+public static final int HTTP_GONE = 410;
+
+/**
+ * A Content-Length header is required for this request, but was not
+ * supplied
+ */
+public static final int HTTP_LENGTH_REQUIRED = 411;
+
+/**
+ * A client specified pre-condition was not met on the server.
+ */
+public static final int HTTP_PRECON_FAILED = 412;
+
+/**
+ * The request sent was too large for the server to handle
+ */
+public static final int HTTP_ENTITY_TOO_LARGE = 413;
+
+/**
+ * The name of the resource specified was too long
+ */
+public static final int HTTP_REQ_TOO_LONG = 414;
+
+/**
+ * The request is in a format not supported by the requested resource
+ */
+public static final int HTTP_UNSUPPORTED_TYPE = 415;
+
+/**
+ * The server encountered an unexpected error (such as a CGI script crash)
+ * that prevents the request from being fulfilled
+ */
+public static final int HTTP_INTERNAL_ERROR = 500;
+
+/**
+ * The server does not support the requested functionality. This code
+ * is specified in RFC 2068, but is not in Sun's JDK 1.2 Beware of using
+ * this variable.
+ */
+public static final int HTTP_NOT_IMPLEMENTED = 501;
+
+/**
+ * The proxy encountered a bad response from the server it was proxy-ing for
+ */
+public static final int HTTP_BAD_GATEWAY = 502;
+
+/**
+ * The HTTP service is not availalble, such as because it is overloaded
+ * and does not want additional requests.
+ */
+public static final int HTTP_UNAVAILABLE = 503;
+
+/**
+ * The proxy timed out getting a reply from the remote server it was
+ * proxy-ing for.
+ */
+public static final int HTTP_GATEWAY_TIMEOUT = 504;
+
+/**
+ * This server does not support the protocol version requested.
+ */
+public static final int HTTP_VERSION = 505;
+
+// Non-HTTP response static variables
+
+/**
+ * Flag to indicate whether or not redirects should be automatically
+ * followed.
+ */
+private static boolean follow_redirects = true;
+
+/**
+ * This is a list of valid request methods, separated by "|" characters.
+ */
+private static String valid_methods = "|GET|POST|HEAD|OPTIONS|PUT|DELETE|TRACE|";
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The requested method in use for this connection.
+ */
+protected String method = "GET"; // GET is the default method
+
+/**
+ * The response code received from the server
+ */
+protected int responseCode = -1;
+
+/**
+ * The response message string received from the server.
+ */
+protected String responseMessage = null;
+
+/*************************************************************************/
+
+/*
+ * Class Methods
+ */
+
+/**
+ * Sets a flag indicating whether or not to automatically follow HTTP
+ * redirects. If not otherwise set, this value defaults to true. Note
+ * that this value cannot be set by applets.
+ *
+ * @param follow true if redirects should be followed, false otherwise
+ */
+public static void
+setFollowRedirectes(boolean follow)
+{
+ follow_redirects = follow;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a boolean indicating whether or not HTTP redirects will
+ * automatically be followed or not.
+ *
+ * @return true if redirects will be followed, false otherwise
+ */
+public static boolean
+getFollowRedirects()
+{
+ return(follow_redirects);
+}
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Create an HttpURLConnection for the specified URL
+ *
+ * @param url The URL to create this connection for.
+ */
+protected
+HttpURLConnection(URL url)
+{
+ super(url);
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * Sets the HTTP request method for this object. Allowable methods are:
+ * GET, POST, HEAD, OPTIONS, PUT, DELETE, and TRACE. Note that not all
+ * protocol implementations will necessarily support all of these
+ * request methods. The default value is GET.
+ *
+ * @param method The request method to use
+ *
+ * @exception ProtocolException If the requested method isn't valid or cannot be used
+ */
+public synchronized void
+setRequestMethod(String method) throws ProtocolException
+{
+ if (valid_methods.indexOf("|" + method.toUpperCase() + "|") == -1)
+ throw new ProtocolException(method.toUpperCase());
+
+ this.method = method;
+}
+
+/*************************************************************************/
+
+/**
+ * The request method currently in use for this connection.
+ *
+ * @exception The request method
+ */
+public String
+getRequestMethod()
+{
+ return(method);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the numeric response code received from the server, or -1 if
+ * no response code has yet been received, or the response code could not
+ * be determined. Note that all valid response codes have class variables
+ * defined for them in this class.
+ *
+ * @return The response code
+ *
+ * @IOException If an error occurs
+ */
+public int
+getResponseCode() throws IOException
+{
+ return(responseCode);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the response message (everything after the response code in the
+ * reply string received from the server) or null if no connection has been
+ * made or no response message could be determined from the server output
+ *
+ * @return The response message
+ *
+ * @exception IOException If an error occurs
+ */
+public String
+getResponseMessage() throws IOException
+{
+ return(responseMessage);
+}
+
+/*************************************************************************/
+
+/**
+ * Closes the connection to the server.
+ */
+public abstract void
+disconnect();
+
+/*************************************************************************/
+
+/**
+ * Returns a boolean indicating whether or not this connection is going
+ * through a proxy
+ *
+ * @return true if through a proxy, false otherwise
+ */
+public abstract boolean
+usingProxy();
+
+} // class HttpURLConnection
+
diff --git a/java/net/InetAddress.java b/java/net/InetAddress.java
new file mode 100644
index 000000000..5bcd3d9d5
--- /dev/null
+++ b/java/net/InetAddress.java
@@ -0,0 +1,661 @@
+/*************************************************************************
+/* InetAddress.java -- Class to model an Internet address
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.Serializable;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+/**
+ * This class models an Internet address. It does not have a public
+ * constructor. Instead, new instances of this objects are created
+ * using the static methods getLocalHost(), getByName(), and
+ * getAllByName().
+ * <p>
+ * This class fulfills the function of the C style functions gethostname(),
+ * gethostbyname(), and gethostbyaddr(). It resolves Internet DNS names
+ * into their corresponding numeric addresses and vice versa.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public final class InetAddress implements Serializable
+{
+
+/*************************************************************************/
+
+/*
+ * Static Variables
+ */
+
+// Static Initializer to load the shared library needed for name resolution
+static
+{
+ System.loadLibrary("javanet");
+}
+
+/**
+ * The default DNS hash table size
+ */
+private static final int DEFAULT_CACHE_SIZE = 400;
+
+/**
+ * The default caching period in minutes
+ */
+private static final int DEFAULT_CACHE_PERIOD = (4 * 60);
+
+/**
+ * Percentage of cache entries to purge when the table gets full
+ */
+private static final int DEFAULT_CACHE_PURGE_PCT = 30;
+
+/**
+ * The special IP address INADDR_ANY
+ */
+private static InetAddress inaddr_any;
+
+/**
+ * The size of the cache
+ */
+private static int cache_size = 0;
+
+/**
+ * The length of time we will continue to read the address from cache
+ * before forcing another lookup
+ */
+private static int cache_period = 0;
+
+/**
+ * What percentage of the cache we will purge if it gets full
+ */
+private static int cache_purge_pct = 0;
+
+/**
+ * Hashtable to use as DNS lookup cache
+ */
+private static Hashtable cache;
+
+// Static initializer for the cache
+static
+{
+ cache_size = DEFAULT_CACHE_SIZE;
+ cache_period = DEFAULT_CACHE_PERIOD * 60 * 1000;
+ cache_purge_pct = DEFAULT_CACHE_PURGE_PCT;
+
+ // Look for properties that override default caching behavior
+ try
+ {
+ String propval;
+
+ propval = System.getProperty("gnu.java.net.dns_cache_size");
+ if (propval != null)
+ cache_size = Integer.parseInt(propval);
+
+ propval = System.getProperty("gnu.java.net.dns_cache_period");
+ cache_period = Integer.parseInt(propval) * 60 * 1000;
+
+ propval = System.getProperty("gnu.java.net.dns_cache_purge_pct");
+ cache_purge_pct = Integer.parseInt(propval);
+ }
+ catch (SecurityException e) { ; }
+ catch (NumberFormatException e) { ; }
+
+ // Fallback to defaults if necessary
+ if ((cache_purge_pct < 1) || (cache_purge_pct > 100))
+ cache_purge_pct = DEFAULT_CACHE_PURGE_PCT;
+
+ // Create the cache
+ if (cache_size != 0)
+ cache = new Hashtable(cache_size);
+}
+
+/*************************************************************************/
+
+/*
+ * Instance variables
+ */
+
+/**
+ * An array of octets representing an IP address
+ */
+int[] my_ip;
+
+/**
+ * The name of the host for this address
+ */
+String hostname;
+
+/**
+ * Backup hostname alias for this address.
+ */
+String hostname_alias;
+
+/**
+ * The time this address was looked up
+ */
+long lookup_time;
+
+/*************************************************************************/
+
+/*
+ * Class Methods
+ */
+
+/**
+ * This method checks the DNS cache to see if we have looked this hostname
+ * up before. If so, we return the cached addresses unless it has been in the
+ * cache too long.
+ *
+ * @param hostname The hostname to check for
+ *
+ * @return The InetAddress for this hostname or null if not available
+ */
+private static synchronized InetAddress[]
+checkCacheFor(String hostname)
+{
+ InetAddress[] addrs = null;
+
+ if (cache_size == 0)
+ return(null);
+
+ Object obj = cache.get(hostname);
+ if (obj == null)
+ return(null);
+
+ if (obj instanceof InetAddress[])
+ addrs = (InetAddress[])obj;
+
+ if (addrs == null)
+ return(null);
+
+ if (cache_period != -1)
+ if ((System.currentTimeMillis() - addrs[0].lookup_time) > cache_period)
+ {
+ cache.remove(hostname);
+ return(null);
+ }
+
+ return(addrs);
+}
+
+/*************************************************************************/
+
+/**
+ * This method adds an InetAddress object to our DNS cache. Note that
+ * if the cache is full, then we run a purge to get rid of old entries.
+ * This will cause a performance hit, thus applications using lots of
+ * lookups should set the cache size to be very large.
+ *
+ * @param hostname The hostname to cache this address under
+ * @param addr The InetAddress or InetAddress array to store
+ */
+private static synchronized void
+addToCache(String hostname, Object addr)
+{
+ if (cache_size == 0)
+ return;
+
+ // Check to see if hash table is full
+ if (cache_size != -1)
+ if (cache.size() == cache_size)
+ {
+ ; //*** Add code to purge later.
+ }
+
+ cache.put(hostname, addr);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the special address INADDR_ANY used for binding to a local
+ * port on all IP addresses hosted by a the local host.
+ *
+ * @return An InetAddress object representing INDADDR_ANY
+ *
+ * @exception UnknownHostException If an error occurs
+ */
+static InetAddress
+getInaddrAny() throws UnknownHostException
+{
+ if (inaddr_any == null)
+ {
+ int[] addr = lookupInaddrAny();
+ inaddr_any = new InetAddress(addr);
+ }
+
+ return(inaddr_any);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an array of InetAddress objects representing all the host/ip
+ * addresses of a given host, given the host's name. This name can be
+ * either a hostname such as "www.urbanophile.com" or an IP address in
+ * dotted decimal format such as "127.0.0.1". If the value is null, the
+ * hostname of the local machine is supplied by default.
+ *
+ * @param hostname The name of the desired host, or null for the local machine
+ *
+ * @return All addresses of the host as an array of InetAddress's
+ *
+ * @exception UnknownHostException If no IP address can be found for the given hostname
+ */
+public static InetAddress[]
+getAllByName(String hostname) throws UnknownHostException
+{
+ // Default to current host if necessary
+ if (hostname == null)
+ {
+ InetAddress addr = getLocalHost();
+ return(getAllByName(addr.getHostName()));
+ }
+
+ // Check the cache for this host before doing a lookup
+ InetAddress[] addrs = checkCacheFor(hostname);
+ if (addrs != null)
+ return(addrs);
+
+ // Not in cache, try the lookup
+ int[][] iplist = getHostByName(hostname);
+ if (iplist.length == 0)
+ throw new UnknownHostException(hostname);
+
+ addrs = new InetAddress[iplist.length];
+
+ for (int i = 0; i < iplist.length; i++)
+ {
+ if (iplist[i].length != 4)
+ throw new UnknownHostException(hostname);
+
+ // Don't store the hostname in order to force resolution of the
+ // canonical names of these ip's when the user asks for the hostname
+ // But do specify the host alias so if the IP returned won't
+ // reverse lookup we don't throw an exception.
+ addrs[i] = new InetAddress(iplist[i], null, hostname);
+ }
+
+ addToCache(hostname, addrs);
+
+ return(addrs);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an InetAddress object representing the IP address of the given
+ * hostname. This name can be either a hostname such as "www.urbanophile.com"
+ * or an IP address in dotted decimal format such as "127.0.0.1". If the
+ * hostname is null, the hostname of the local machine is supplied by
+ * default. This method is equivalent to returning the first element in
+ * the InetAddress array returned from GetAllByName.
+ *
+ * @param hostname The name of the desired host, or null for the local machine
+ *
+ * @return The address of the host as an InetAddress
+ *
+ * @exception UnknownHostException If no IP address can be found for the given hostname
+ */
+public static InetAddress
+getByName(String hostname) throws UnknownHostException
+{
+ // Default to current host if necessary
+ if (hostname == null)
+ return(getLocalHost());
+
+ // First, check to see if it is an IP address. If so, then don't
+ // do a DNS lookup.
+ StringTokenizer st = new StringTokenizer(hostname, ".");
+ if (st.countTokens() == 4)
+ {
+ int i;
+ int[] ip = new int[4];
+ for (i = 0; i < 4; i++)
+ {
+ try
+ {
+ ip[i] = Integer.parseInt(st.nextToken());
+ if ((ip[i] < 0) || (ip[1] > 255))
+ break;
+ }
+ catch (NumberFormatException e)
+ {
+ break;
+ }
+ }
+ if (i == 4)
+ {
+ return(new InetAddress(ip));
+ }
+ }
+
+ // Wasn't and IP, so try the lookup
+ InetAddress[] addrs = getAllByName(hostname);
+
+ return(addrs[0]);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an InetAddress object representing the address of the current
+ * host.
+ *
+ * @return The local host's address
+ *
+ * @exception UnknownHostException If an error occurs
+ */
+public static InetAddress
+getLocalHost() throws UnknownHostException
+{
+ String hostname = getLocalHostName();
+
+ return(getByName(hostname));
+}
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Initializes this object's my_ip instance variable from the passed in
+ * int array. Note that this constructor is protected and is called
+ * only by static methods in this class.
+ *
+ * @param addr The IP number of this address as an array of bytes
+ */
+private
+InetAddress(int[] addr)
+{
+ this(addr, null, null);
+}
+
+/*************************************************************************/
+
+/**
+ * Initializes this object's my_ip instance variable from the passed in
+ * int array. Note that this constructor is protected and is called
+ * only by static methods in this class.
+ *
+ * @param addr The IP number of this address as an array of bytes
+ * @param hostname The hostname of this IP address.
+ */
+private
+InetAddress(int[] addr, String hostname)
+{
+ this(addr, hostname, null);
+}
+
+/*************************************************************************/
+
+/**
+ * Initializes this object's my_ip instance variable from the passed in
+ * int array. Note that this constructor is protected and is called
+ * only by static methods in this class.
+ *
+ * @param addr The IP number of this address as an array of bytes
+ * @param hostname The hostname of this IP address.
+ * @param hostname_alias A backup hostname to use if hostname is null to prevent reverse lookup failures
+ */
+private
+InetAddress(int[] addr, String hostname, String hostname_alias)
+{
+ my_ip = new int[addr.length];
+
+ for (int i = 0; i < addr.length; i++)
+ my_ip[i] = addr[i];
+
+ this.hostname = hostname;
+ this.hostname_alias = hostname_alias;
+ lookup_time = System.currentTimeMillis();
+}
+
+/*************************************************************************/
+
+/**
+ * Instance Methods
+ */
+
+/**
+ * Tests this address for equality against another InetAddress. The two
+ * addresses are considered equal if they contain the exact same octets.
+ * This implementation overrides Object.equals()
+ *
+ * @param addr The address to test for equality
+ *
+ * @return true if the passed in object's address is equal to this one's, false otherwise
+ */
+public boolean
+equals(Object addr)
+{
+ if (!(addr instanceof InetAddress))
+ return(false);
+
+ byte[] test_ip = ((InetAddress)addr).getAddress();
+
+ if (test_ip.length != my_ip.length)
+ return(false);
+
+ for (int i = 0; i < my_ip.length; i++)
+ if (test_ip[i] != (byte)my_ip[i])
+ return(false);
+
+ return(true);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the IP address of this object as a int array.
+ *
+ * @return IP address
+ */
+public byte[]
+getAddress()
+{
+ byte[] addr = new byte[my_ip.length];
+
+ for (int i = 0; i < my_ip.length; i++)
+ {
+ addr[i] = (byte)my_ip[i];
+ }
+
+ return(addr);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the IP address of this object as a String. The address is in
+ * the dotted octet notation, for example, "127.0.0.1".
+ *
+ * @return The IP address of this object in String form
+ */
+public String
+getHostAddress()
+{
+ StringBuffer addr = new StringBuffer();
+
+ for (int i = 0; i < my_ip.length; i++)
+ {
+ addr.append((int)my_ip[i]);
+ if (i < (my_ip.length - 1))
+ addr.append(".");
+ }
+
+ return(addr.toString());
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the hostname for this address. This will return the IP address
+ * as a String if there is no hostname available for this address
+ *
+ * @return The hostname for this address
+ */
+public String
+getHostName()
+{
+ if (hostname != null)
+ return(hostname);
+
+ try
+ {
+ hostname = getHostByAddr(my_ip);
+ return(hostname);
+ }
+ catch (UnknownHostException e)
+ {
+ if (hostname_alias != null)
+ return(hostname_alias);
+ else
+ return(getHostAddress());
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a hash value for this address. Useful for creating hash
+ * tables. Overrides Object.hashCode()
+ *
+ * @return A hash value for this address.
+ */
+public int
+hashCode()
+{
+ long val1 = 0, val2 = 0;
+
+ // Its obvious here that I have no idea how to generate a good
+ // hash key
+ for (int i = 0; i < my_ip.length; i++)
+ val1 = val1 + (my_ip[i] << ((my_ip.length - i) / 8));
+
+ for (int i = 0; i < my_ip.length; i++)
+ val2 = val2 + (my_ip[i] * 10 * i);
+
+ val1 = (val1 >> 1) ^ val2;
+
+ return((int)val1);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns true if this address is a multicast address, false otherwise.
+ * An address is multicast if the high four bits are "1110". These are
+ * also known as "Class D" addresses.
+ *
+ * @return true if mulitcast, false if not
+ */
+public boolean
+isMulticastAddress()
+{
+ if (my_ip.length == 0)
+ return(false);
+
+ // Mask against high order bits of 1110
+ if ((my_ip[0] & 224) == 224)
+ return(true);
+
+ return(false);
+}
+
+/*************************************************************************/
+
+/**
+ * Converts this address to a String. This string contains the IP in
+ * dotted decimal form. For example: "127.0.0.1" This method is equivalent
+ * to getHostAddress() and overrides Object.toString()
+ *
+ * @return This address in String form
+ */
+public String
+toString()
+{
+ return(getHostAddress());
+}
+
+/*************************************************************************/
+
+/*
+ * Native Methods
+ */
+
+/**
+ * This native method looks up the hostname of the local machine
+ * we are on. If the actual hostname cannot be determined, then the
+ * value "localhost" we be used. This native method wrappers the
+ * "gethostname" function.
+ *
+  * @return The local hostname.
+ */
+private static native String
+getLocalHostName();
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the special address INADDR_ANY
+ */
+private static native int[]
+lookupInaddrAny() throws UnknownHostException;
+
+/*************************************************************************/
+
+/**
+ * This method returns the hostname for a given IP address. It will
+ * throw an UnknownHostException if the hostname cannot be determined.
+ *
+ * @param ip The IP address as a int arrary
+ *
+ * @return The hostname
+ *
+ * @exception UnknownHostException If the reverse lookup fails
+ */
+private static native String
+getHostByAddr(int[] ip) throws UnknownHostException;
+
+/*************************************************************************/
+
+/**
+ * Returns a list of all IP addresses for a given hostname. Will throw
+ * an UnknownHostException if the hostname cannot be resolved.
+ */
+private static native int[][]
+getHostByName(String hostname) throws UnknownHostException;
+
+/*************************************************************************/
+
+public static void
+main(String[] argv)
+{
+ System.out.println("The name of the local host is: " +
+ getLocalHostName());
+}
+
+} // class InetAddress
+
+
diff --git a/java/net/JarURLConnection.java b/java/net/JarURLConnection.java
new file mode 100644
index 000000000..64f445f96
--- /dev/null
+++ b/java/net/JarURLConnection.java
@@ -0,0 +1,237 @@
+/*************************************************************************
+/* JarURLConnection.java -- Class for manipulating remote jar files
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.IOException;
+import java.security.Identity;
+import java.util.jar.*;
+
+/**
+ * This abstract class represents a common superclass for implementations
+ * of jar URL's. A jar URL is a special type of URL that allows JAR
+ * files on remote systems to be accessed. It has the form:
+ * <p>
+ * jar:<standard URL pointing to jar file>!/file/within/jarfile
+ * <p> for example:
+ * <p>
+ * jar:http://www.urbanophile.com/java/foo.jar!/com/urbanophile/bar.class
+ * <p>
+ * That example URL points to the file /com/urbanophile/bar.class in the
+ * remote JAR file http://www.urbanophile.com/java/foo.jar. The HTTP
+ * protocol is used only as an example. Any supported remote protocol
+ * can be used.
+ * <p>
+ * This class currently works by retrieving the entire jar file into a
+ * local cache file, then performing standard jar operations on it.
+ * (At least this is true for the default protocol implementation).
+ *
+ * @version 0.1
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract class JarURLConnection extends URLConnection
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * This is the actual URL that points the remote jar file. This is parsed
+ * out of the jar URL by the constructor.
+ */
+private URL real_url;
+
+/**
+ * This is the jar file "entry name" or portion after the "!/" in the
+ * URL which represents the pathname inside the actual jar file
+ */
+private String entry_name;
+
+/**
+ * The JarFile object for the jar file pointed to by the real URL
+ */
+private JarFile jar_file;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Creates a JarURLConnection from a URL objects
+ *
+ * @param URL url The URL object for this connection.
+ */
+protected
+JarURLConnection(URL url) throws MalformedURLException
+{
+ super(url);
+
+ // Now, strip off the "jar:" and everything from the "!/" to the end
+ // to get the "real" URL inside
+ String url_string = url.toExternalForm();
+
+ if (!url_string.startsWith("jar:"))
+ throw new MalformedURLException(url_string);
+
+ if (url_string.indexOf("!/") == -1)
+ throw new MalformedURLException(url_string);
+
+ String real_url_string = url_string.substring(4, url_string.indexOf("!/") - 4);
+
+ real_url = new URL(real_url_string);
+ if (url_string.length() == (url_string.indexOf("!/") + 1))
+ entry_name = "";
+ else
+ entry_name = url_string.substring(url_string.indexOf("!/") + 2);
+}
+
+/*************************************************************************/
+
+/**
+ * This method returns the "real" URL where the JarFile is located.
+ * //****Is this right?*****
+ *
+ * @return The remote URL
+ */
+public URL
+getJarFileURL()
+{
+ return(real_url);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the "entry name" portion of the jar URL. This is the portion
+ * after the "!/" in the jar URL that represents the pathname inside the
+ * actual jar file.
+ *
+ * @return The entry name.
+ */
+public String
+getEntryName()
+{
+ return(entry_name);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a read-only JarFile object for the remote jar file
+ *
+ * @return The JarFile object
+ *
+ * @exception IOException If an error occurs
+ */
+public abstract JarFile
+getJarFile() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Returns a Manifest object for this jar file, or null if there is no
+ * manifest.
+ *
+ * @return The Manifest
+ *
+ * @exception IOException If an error occurs
+ */
+public Manifest
+getManifest() throws IOException
+{
+ if (jar_file == null)
+ jar_file = getJarFile();
+
+ return(jar_file.getManifest());
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the entry in this jar file specified by the URL.
+ *
+ * @return The jar entry
+ *
+ * @exception IOException If an error occurs
+ */
+public JarEntry
+getJarEntry() throws IOException
+{
+ if (jar_file == null)
+ jar_file = getJarFile();
+
+ return(jar_file.getJarEntry(entry_name));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the Attributes for the Jar entry specified by the URL or null
+ * if none
+ *
+ * @return The Attributes
+ *
+ * @exception IOException If an error occurs
+ */
+public Attributes
+getAttributes() throws IOException
+{
+ return(getJarEntry().getAttributes());
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the main Attributes for the jar file specified in the URL or
+ * null if there are none
+ *
+ * @return The main Attributes
+ *
+ * @exception IOException If an error occurs
+ */
+public Attributes
+getMainAttributes() throws IOException
+{
+ return(getManifest().getMainAttributes());
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an array of Identity objects for the jar file entry specified
+ * by this URL or null if there are none
+ *
+ * @return An Identity array
+ *
+ * @exception IOException If an error occurs
+ */
+public Identity[]
+getIdentities() throws IOException
+{
+ return(getJarEntry().getIdentities());
+}
+
+} // class JarURLConnection
+
diff --git a/java/net/Makefile.am b/java/net/Makefile.am
new file mode 100644
index 000000000..ac7e42ae2
--- /dev/null
+++ b/java/net/Makefile.am
@@ -0,0 +1,23 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+javanetdir = $(datadir)/java/net
+
+javanet_JAVA = BindException.java ConnectException.java ContentHandler.java \
+ ContentHandlerFactory.java DatagramPacket.java \
+ DatagramSocket.java DatagramSocketImpl.java FileNameMap.java \
+ HttpURLConnection.java InetAddress.java \
+ MalformedURLException.java \
+ MimeTypeMapper.java MulticastSocket.java \
+ NoRouteToHostException.java PasswordAuthentication.java \
+ PlainDatagramSocketImpl.java PlainSocketImpl.java \
+ ProtocolException.java ServerSocket.java Socket.java \
+ SocketException.java SocketImpl.java SocketImplFactory.java \
+ SocketInputStream.java SocketOptions.java \
+ SocketOutputStream.java URL.java URLConnection.java \
+ URLEncoder.java URLStreamHandler.java \
+ URLStreamHandlerFactory.java UnknownHostException.java \
+ UnknownServiceException.java
+
+EXTRA_DIST = Authenticator.java JarURLConnection.java NetPermission.java \
+ SocketPermission.java STATUS TODO
+
diff --git a/java/net/MalformedURLException.java b/java/net/MalformedURLException.java
new file mode 100644
index 000000000..a7419c0d8
--- /dev/null
+++ b/java/net/MalformedURLException.java
@@ -0,0 +1,61 @@
+/*************************************************************************
+/* MalformedURLException.java -- A URL was not in a valid format
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This exception indicates that a URL passed to an object was not in a
+ * valid format.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class MalformedURLException extends java.io.IOException
+{
+
+/*
+ * Constructors
+ */
+
+/**
+ * Constructs a new MalformedURLException with no descriptive message.
+ */
+public
+MalformedURLException()
+{
+ super();
+}
+
+/*************************************************************************/
+
+/**
+ * Constructs a new MalformedURLException with a descriptive message
+ * passed in as an argument.
+ *
+ * @param message A message describing the error that occurs
+ */
+public
+MalformedURLException(String message)
+{
+ super(message);
+}
+
+} // class MalformedURLException
+
diff --git a/java/net/MimeTypeMapper.java b/java/net/MimeTypeMapper.java
new file mode 100644
index 000000000..dc9a639a2
--- /dev/null
+++ b/java/net/MimeTypeMapper.java
@@ -0,0 +1,216 @@
+/*************************************************************************
+/* MimeTypeMapper.java -- A class for mapping file names to MIME types
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.util.Hashtable;
+
+/**
+ * This non-public class is used to implement the FileNameMap interface
+ * which defines a mechanism for mapping filenames to MIME types.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+class MimeTypeMapper implements FileNameMap
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
+ */
+
+/**
+ * This array of strings is used to identify a MIME type based on a file
+ * extension. This is list is based on the Apache mime.types file.
+ */
+protected static final String[][] mime_strings = {
+ { "application/mac-binhex40", "hqx" },
+ { "application/mac-compactpro", "cpt" },
+ { "application/msword", "doc" },
+ { "application/octet-stream", "bin" },
+ { "application/octet-stream", "dms" },
+ { "application/octet-stream", "lha" },
+ { "application/octet-stream", "lzh" },
+ { "application/octet-stream", "exe" },
+ { "application/octet-stream", "class" },
+ { "application/oda", "oda" },
+ { "application/pdf", "pdf" },
+ { "application/postscript", "ai" },
+ { "application/postscript", "eps" },
+ { "application/postscript", "ps" },
+ { "application/powerpoint", "ppt" },
+ { "application/rtf", "rtf" },
+ { "application/x-bcpio", "bcpio" },
+ { "application/x-cdlink", "vcd" },
+ { "application/x-compress", "Z" },
+ { "application/x-cpio", "cpio" },
+ { "application/x-csh", "csh" },
+ { "application/x-director", "dcr" },
+ { "application/x-director", "dir" },
+ { "application/x-director", "dxr" },
+ { "application/x-dvi", "dvi" },
+ { "application/x-gtar", "gtar" },
+ { "application/x-gzip", "gz" },
+ { "application/x-hdf", "hdf" },
+ { "application/x-httpd-cgi", "cgi" },
+ { "application/x-koan", "skp" },
+ { "application/x-koan", "skd" },
+ { "application/x-koan", "skt" },
+ { "application/x-koan", "skm" },
+ { "application/x-latex", "latex" },
+ { "application/x-mif", "mif" },
+ { "application/x-netcdf", "nc" },
+ { "application/x-netcdf", "cdf" },
+ { "application/x-sh", "sh" },
+ { "application/x-shar", "shar" },
+ { "application/x-stuffit", "sit" },
+ { "application/x-sv4cpio", "sv4cpio" },
+ { "application/x-sv4crc", "sv4crc" },
+ { "application/x-tar", "tar" },
+ { "application/x-tcl", "tcl" },
+ { "application/x-tex", "tex" },
+ { "application/x-texinfo", "texinfo" },
+ { "application/x-texinfo", "texi" },
+ { "application/x-troff", "t" },
+ { "application/x-troff", "tr" },
+ { "application/x-troff", "roff" },
+ { "application/x-troff-man", "man" },
+ { "application/x-troff-me", "me" },
+ { "application/x-troff-ms", "ms" },
+ { "application/x-ustar", "ustar" },
+ { "application/x-wais-source", "src" },
+ { "application/zip", "zip" },
+ { "audio/basic", "au" },
+ { "audio/basic", "snd" },
+ { "audio/mpeg", "mpga" },
+ { "audio/mpeg", "mp2" },
+ { "audio/mpeg", "mp3" },
+ { "audio/x-aiff", "aif" },
+ { "audio/x-aiff", "aiff" },
+ { "audio/x-aiff", "aifc" },
+ { "audio/x-pn-realaudio", "ram" },
+ { "audio/x-pn-realaudio-plugin", "rpm" },
+ { "audio/x-realaudio", "ra" },
+ { "audio/x-wav", "wav" },
+ { "chemical/x-pdb", "pdb" },
+ { "chemical/x-pdb", "xyz" },
+ { "image/gif", "gif" },
+ { "image/ief", "ief" },
+ { "image/jpeg", "jpeg" },
+ { "image/jpeg", "jpg" },
+ { "image/jpeg", "jpe" },
+ { "image/png", "png" },
+ { "image/tiff", "tiff" },
+ { "image/tiff", "tif" },
+ { "image/x-cmu-raster", "ras" },
+ { "image/x-portable-anymap", "pnm" },
+ { "image/x-portable-bitmap", "pbm" },
+ { "image/x-portable-graymap", "pgm" },
+ { "image/x-portable-pixmap", "ppm" },
+ { "image/x-rgb", "rgb" },
+ { "image/x-xbitmap", "xbm" },
+ { "image/x-xpixmap", "xpm" },
+ { "image/x-xwindowdump", "xwd" },
+ { "text/html", "html" },
+ { "text/html", "htm" },
+ { "text/plain", "txt" },
+ { "text/richtext", "rtx" },
+ { "text/tab-separated-values", "tsv" },
+ { "text/x-setext", "etx" },
+ { "text/x-sgml", "sgml" },
+ { "text/x-sgml", "sgm" },
+ { "video/mpeg", "mpeg" },
+ { "video/mpeg", "mpg" },
+ { "video/mpeg", "mpe" },
+ { "video/quicktime", "qt" },
+ { "video/quicktime", "mov" },
+ { "video/x-msvideo", "avi" },
+ { "video/x-sgi-movie", "movie" },
+ { "x-conference/x-cooltalk", "ice" },
+ { "x-world/x-vrml", "wrl" },
+ { "x-world/x-vrml", "vrml" }
+ };
+
+/**
+ * The MIME types above are put into this Hashtable for faster lookup.
+ */
+private static Hashtable mime_types = new Hashtable(150);
+
+// Static initializer to load MIME types into Hashtable
+static
+{
+ for (int i = 0; i < mime_strings.length; i++)
+ mime_types.put(mime_strings[i][1], mime_strings[i][0]);
+}
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * A do nothing constructor
+ */
+public
+MimeTypeMapper()
+{
+ ;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The method returns the MIME type of the filename passed as an argument.
+ * The value returned is based on the extension of the filename. The
+ * default content type returned if this method cannot determine the
+ * actual content type is "application/octet-stream"
+ *
+ * @param filename The name of the file to return the MIME type for
+ *
+ * @return The MIME type
+ */
+public String
+getContentTypeFor(String filename)
+{
+ int index = filename.lastIndexOf(".");
+ if (index != -1)
+ {
+ if (index == filename.length())
+ return("application/octet-stream");
+ else
+ filename = filename.substring(index + 1);
+ }
+
+ String type = (String)mime_types.get(filename);
+ if (type == null)
+ return("application/octet-stream");
+ else
+ return(type);
+}
+
+} // class MimeTypeMapper
+
diff --git a/java/net/MulticastSocket.java b/java/net/MulticastSocket.java
new file mode 100644
index 000000000..029357f4e
--- /dev/null
+++ b/java/net/MulticastSocket.java
@@ -0,0 +1,197 @@
+/*************************************************************************
+/* MulticastSocket.java -- Class for using multicast sockets
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * This class models a multicast UDP socket. A multicast address is a
+ * class D internet address (one whose most significant bits are 1110).
+ * A multicast group consists of a multicast address and a well known
+ * port number. All members of the group listening on that address and
+ * port will receive all the broadcasts to the group.
+ * <p>
+ * Please note that applets are not allowed to use multicast sockets
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class MulticastSocket extends DatagramSocket
+{
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Create a MulticastSocket that this not bound to any address
+ *
+ * @exception IOException If an error occurs
+ */
+public
+MulticastSocket() throws IOException
+{
+ super();
+}
+
+/*************************************************************************/
+
+/**
+ * Create a multicast socket bound to the specified port
+ *
+ * @param The port to bind to
+ *
+ * @exception IOException If an error occurs
+ */
+public
+MulticastSocket(int port) throws IOException
+{
+ super(port);
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * Returns the current value of the "Time to Live" option. This is the
+ * number of hops a packet can make before it "expires".
+ *
+ * @return The TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized byte
+getTTL() throws IOException
+{
+ return(impl.getTTL());
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the "Time to Live" value for a socket. The value must be between
+ * 1 and 255.
+ *
+ * @param ttl The new TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+setTTL(byte ttl) throws IOException
+{
+ impl.setTTL(ttl);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the interface being used for multicast packets
+ *
+ * @return The multicast interface
+ *
+ * @exception SocketException If an error occurs
+ */
+public synchronized InetAddress
+getInterface() throws SocketException
+{
+ Object obj;
+
+ obj = impl.getOption(SocketOptions.IP_MULTICAST_IF);
+
+ if (!(obj instanceof InetAddress))
+ throw new SocketException("Internal Error");
+
+ return(((InetAddress)obj));
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the interface to use for multicast packets.
+ *
+ * @param addr The new interface to use
+ *
+ * @exception SocketException If an error occurs
+ */
+public synchronized void
+setInterface(InetAddress addr) throws SocketException
+{
+ impl.setOption(SocketOptions.IP_MULTICAST_IF, addr);
+}
+
+/*************************************************************************/
+
+/**
+ * Joins the specified mulitcast group.
+ *
+ * @param addr The address of the group to join
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+joinGroup(InetAddress addr) throws IOException
+{
+ impl.join(addr);
+}
+
+/*************************************************************************/
+
+/**
+ * Leaves the specified multicast group
+ *
+ * @param addr The address of the group to leave
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+leaveGroup(InetAddress addr) throws IOException
+{
+ impl.leave(addr);
+}
+
+/*************************************************************************/
+
+/**
+ * Sends a packet of data to a multicast address with a TTL that is
+ * different from the default TTL on this socket. The default TTL for
+ * the socket is not changed.
+ *
+ * @param packet The packet of data to send
+ * @param ttl The TTL for this packet
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+send(DatagramPacket packet, byte ttl) throws IOException
+{
+ byte old_ttl = getTTL();
+ setTTL(ttl);
+ send(packet);
+ setTTL(old_ttl);
+}
+
+} // class MulticastSocket
+
diff --git a/java/net/NetPermission.java b/java/net/NetPermission.java
new file mode 100644
index 000000000..4cf96c982
--- /dev/null
+++ b/java/net/NetPermission.java
@@ -0,0 +1,72 @@
+/*************************************************************************
+/* NetPermission.java -- A class for basic miscellaneous network permission
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.security.BasicPermission;
+
+/**
+ * This class is used to model miscellaneous network permissions. It is
+ * a subclass of BasicPermission. This means that it models a "boolean"
+ * permission. One that you either have or do not have. Thus there is
+ * no permitted action list associated with this object.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public final class NetPermission extends BasicPermission
+{
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Creates a new NetPermission with the specified name which is any valid
+ * String.
+ *
+ * @param name The name of this permission
+ */
+public
+NetPermission(String name)
+{
+ super(name);
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a new NetPermission with the specified name and value. Note that
+ * the value field is irrelevant and is ignored. This constructor should
+ * never need to be used.
+ *
+ * @param name The name of this permission
+ * @param perms The permitted actions of this permission (ignored)
+ */
+public
+NetPermission(String name, String perms)
+{
+ super(name);
+}
+
+} // class NetPermission
+
diff --git a/java/net/NoRouteToHostException.java b/java/net/NoRouteToHostException.java
new file mode 100644
index 000000000..64322529d
--- /dev/null
+++ b/java/net/NoRouteToHostException.java
@@ -0,0 +1,61 @@
+/*************************************************************************
+/* NoRouteToHostException.java -- Cannot connect to a host
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This exception indicates that there is no TCP/IP route to the requested
+ * host. This is often due to a misconfigured routing table.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class NoRouteToHostException extends SocketException
+{
+
+/*
+ * Constructors
+ */
+
+/**
+ * Constructs a new NoRouteToHostException with no descriptive message.
+ */
+public
+NoRouteToHostException()
+{
+ super();
+}
+
+/*************************************************************************/
+
+/**
+ * Constructs a new NoRouteToHostException with a descriptive message (such as the
+ * text from strerror(3)) passed in as an argument
+ *
+ * @param message A message describing the error that occurs
+ */
+public
+NoRouteToHostException(String message)
+{
+ super(message);
+}
+
+} // class NoRouteToHostException
+
diff --git a/java/net/PasswordAuthentication.java b/java/net/PasswordAuthentication.java
new file mode 100644
index 000000000..88f469d23
--- /dev/null
+++ b/java/net/PasswordAuthentication.java
@@ -0,0 +1,99 @@
+/*************************************************************************
+/* PasswordAuthentication.java -- Container class for username/password pairs
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This class serves a container for username/password pairs.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public final class PasswordAuthentication
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The username
+ */
+protected String username;
+
+/**
+ * The password
+ */
+protected String password;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Creates a new PasswordAuthentication object from the specified username
+ * and password.
+ *
+ * @param username The username for this object
+ * @param password The password for this object
+ */
+public
+PasswordAuthentication(String username, String password)
+{
+ this.username = username;
+ this.password = password;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * Returns the username associated with this object
+ *
+ * @return The username
+ */
+public String
+getUsername()
+{
+ return(username);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the password associated with this object
+ *
+ * @return The password
+ */
+public String
+getPassword()
+{
+ return(password);
+}
+
+} // class PasswordAuthentication
+
diff --git a/java/net/PlainDatagramSocketImpl.java b/java/net/PlainDatagramSocketImpl.java
new file mode 100644
index 000000000..356f3f0c9
--- /dev/null
+++ b/java/net/PlainDatagramSocketImpl.java
@@ -0,0 +1,250 @@
+/*************************************************************************
+/* PlainDatagramSocketImpl.java -- Default DatagramSocket implementation
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * This is the default socket implementation for datagram sockets.
+ * It makes native calls to C routines that implement BSD style
+ * SOCK_DGRAM sockets in the AF_INET family.
+ *
+ * @version 0.1
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class PlainDatagramSocketImpl extends DatagramSocketImpl
+{
+
+/*************************************************************************/
+
+/*
+ * Static Variables
+ */
+
+// Static initializer to load native library
+static
+{
+ System.loadLibrary("javanet");
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * This is the actual underlying file descriptor
+ */
+protected int native_fd = -1;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Default do nothing constructor
+ */
+public
+PlainDatagramSocketImpl()
+{
+ ;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * Creates a new datagram socket
+ *
+ * @exception SocketException If an error occurs
+ */
+protected native synchronized void
+create() throws SocketException;
+
+/*************************************************************************/
+
+/**
+ * Closes the socket
+ */
+protected native synchronized void
+close();
+
+/*************************************************************************/
+
+/**
+ * Binds this socket to a particular port and interface
+ *
+ * @param port The port to bind to
+ * @param addr The address to bind to
+ *
+ * @exception SocketException If an error occurs
+ */
+protected native synchronized void
+bind(int port, InetAddress addr) throws SocketException;
+
+/*************************************************************************/
+
+/**
+ * Sends a packet of data to a remote host
+ *
+ * @param packet The packet to send
+ *
+ * @exception IOException If an error occurs
+ */
+protected synchronized void
+send(DatagramPacket packet) throws IOException
+{
+ sendto(packet.getAddress(), packet.getPort(), packet.getData(),
+ packet.getLength());
+}
+
+/*************************************************************************/
+
+/**
+ * Sends a packet of data to a remote host
+ *
+ * @param addr The address to send to
+ * @param port The port to send to
+ * @param buf The buffer to send
+ * @param len The length of the data to send
+ *
+ * @exception IOException If an error occurs
+ */
+private native synchronized void
+sendto(InetAddress addr, int port, byte[] buf, int len) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * What does this method really do?
+ */
+protected synchronized int
+peek(InetAddress addr) throws IOException
+{
+ throw new IOException("Not Implemented Yet");
+}
+
+/*************************************************************************/
+
+/**
+ * Receives a UDP packet from the network
+ *
+ * @param packet The packet to fill in with the data received
+ *
+ * @exception IOException IOException If an error occurs
+ */
+protected native synchronized void
+receive(DatagramPacket packet) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Joins a multicast group
+ *
+ * @param addr The group to join
+ *
+ * @exception IOException If an error occurs
+ */
+protected native synchronized void
+join(InetAddress addr) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Leaves a multicast group
+ *
+ * @param addr The group to leave
+ *
+ * @exception IOException If an error occurs
+ */
+protected native synchronized void
+leave(InetAddress addr) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Gets the Time to Live value for the socket
+ *
+ * @return The TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+protected synchronized byte
+getTTL() throws IOException
+{
+ Object obj = getOption(SocketOptions.IP_TTL);
+
+ if (!(obj instanceof Integer))
+ throw new IOException("Internal Error");
+
+ return(((Integer)obj).byteValue());
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the Time to Live value for the socket
+ *
+ * @param ttl The new TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+protected synchronized void
+setTTL(byte ttl) throws IOException
+{
+ setOption(SocketOptions.IP_TTL, new Integer(ttl));
+}
+
+/*************************************************************************/
+
+/**
+ * Retrieves the value of an option on the socket
+ *
+ * @param option_id The identifier of the option to retrieve
+ *
+ * @return The value of the option
+ *
+ * @exception SocketException If an error occurs
+ */
+public native synchronized Object
+getOption(int option_id) throws SocketException;
+
+/*************************************************************************/
+
+/**
+ * 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
+ *
+ * @exception SocketException If an error occurs
+ */
+public native synchronized void
+setOption(int option_id, Object val) throws SocketException;
+
+} // class PlainDatagramSocketImpl
+
diff --git a/java/net/PlainSocketImpl.java b/java/net/PlainSocketImpl.java
new file mode 100644
index 000000000..448f7f10d
--- /dev/null
+++ b/java/net/PlainSocketImpl.java
@@ -0,0 +1,285 @@
+/*************************************************************************
+/* PlainSocketImpl.java -- Default socket implementation
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Unless the application installs its own SocketImplFactory, this is the
+ * default socket implemetation that will be used. It simply uses a
+ * combination of Java and native routines to implement standard BSD
+ * style sockets of family AF_INET and types SOCK_STREAM and SOCK_DGRAM
+ *
+ * @version 0.1
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+class PlainSocketImpl extends SocketImpl
+{
+
+/*************************************************************************/
+
+/*
+ * Static Variables
+ */
+
+// Static initializer to load native library
+static
+{
+ System.loadLibrary("javanet");
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * This is the native file descriptor for this socket
+ */
+protected int native_fd = -1;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Default do nothing constructor
+ */
+public
+PlainSocketImpl()
+{
+ ;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * Accepts a new connection on this socket and returns in in the
+ * passed in SocketImpl.
+ *
+ * @param impl The SocketImpl object to accept this connection.
+ */
+protected native synchronized void
+accept(SocketImpl impl) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Returns the number of bytes that the caller can read from this socket
+ * without blocking. //*****Figure out if we can do something here
+ *
+ * @return The number of readable bytes before blocking
+ *
+ * @exception IOException If an error occurs
+ */
+protected int
+available() throws IOException
+{
+ return(0);
+}
+
+/*************************************************************************/
+
+/**
+ * Binds to the specified port on the specified addr. Note that this addr
+ * must represent a local IP address. **** How bind to INADDR_ANY? ****
+ *
+ * @param addr The address to bind to
+ * @param port The port number to bind to
+ *
+ * @exception IOException If an error occurs
+ */
+protected native synchronized void
+bind(InetAddress addr, int port) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Closes the socket. This will cause any InputStream or OutputStream
+ * objects for this Socket to be closed as well.
+ * <p>
+ * Note that if the SO_LINGER option is set on this socket, then the
+ * operation could block.
+ *
+ * @exception IOException If an error occurs
+ */
+protected native synchronized void
+close() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Connects to the remote address and port specified as arguments.
+ *
+ * @param addr The remote address to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+protected native synchronized void
+connect(InetAddress addr, int port) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Connects to the remote hostname and port specified as arguments.
+ *
+ * @param hostname The remote hostname to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+protected synchronized void
+connect(String hostname, int port) throws IOException
+{
+ InetAddress addr = InetAddress.getByName(hostname);
+ connect(addr, port);
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a new socket that is not bound to any local address/port and
+ * is not connected to any remote address/port. This will be created as
+ * a stream socket if the stream parameter is true, or a datagram socket
+ * if the stream parameter is false.
+ *
+ * @param stream true for a stream socket, false for a datagram socket
+ */
+protected native synchronized void
+create(boolean stream) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Starts listening for connections on a socket. The queuelen parameter
+ * is how many pending connections will queue up waiting to be serviced
+ * before being accept'ed. If the queue of pending requests exceeds this
+ * number, additional connections will be refused.
+ *
+ * @param queuelen The length of the pending connection queue
+ *
+ * @exception IOException If an error occurs
+ */
+protected native synchronized void
+listen(int queuelen) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Internal method used by SocketInputStream for reading data from
+ * the connection. Reads up to len bytes of data into the buffer
+ * buf starting at offset bytes into the buffer.
+ *
+ * @return The actual number of bytes read or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs
+ */
+protected native synchronized int
+read(byte[] buf, int offset, int len) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Internal method used by SocketOuputStream for writing data to
+ * the connection. Writes up to len bytes of data from the buffer
+ * buf starting at offset bytes into the buffer.
+ *
+ * @exception IOException If an error occurs
+ */
+protected native synchronized void
+write(byte[] buf, int offset, int len) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Sets the specified option on a socket to the passed in object. For
+ * options that take an integer argument, the passed in object is an
+ * Integer. The option_id parameter is one of the defined constants in
+ * this interface.
+ *
+ * @param option_id The identifier of the option
+ * @param val The value to set the option to
+ *
+ * @exception SocketException If an error occurs
+ */
+public native synchronized void
+setOption(int option_id, Object val) throws SocketException;
+
+/*************************************************************************/
+
+/**
+ * Returns the current setting of the specified option. The Object returned
+ * will be an Integer for options that have integer values. The option_id
+ * is one of the defined constants in this interface.
+ *
+ * @param option_id The option identifier
+ *
+ * @return The current value of the option
+ *
+ * @exception SocketException If an error occurs
+ */
+public native synchronized Object
+getOption(int option_id) throws SocketException;
+
+/*************************************************************************/
+
+/**
+ * Returns an InputStream object for reading from this socket. This will
+ * be an instance of SocketInputStream.
+ *
+ * @return An InputStream
+ *
+ * @exception IOException If an error occurs
+ */
+protected synchronized InputStream
+getInputStream() throws IOException
+{
+ return(new SocketInputStream(this));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an OutputStream object for writing to this socket. This will
+ * be an instance of SocketOutputStream.
+ *
+ * @return An OutputStream
+ *
+ * @exception IOException If an error occurs
+ */
+protected synchronized OutputStream
+getOutputStream() throws IOException
+{
+ return(new SocketOutputStream(this));
+}
+
+} // class PlainSocketImpl
+
diff --git a/java/net/ProtocolException.java b/java/net/ProtocolException.java
new file mode 100644
index 000000000..a1d3da1f9
--- /dev/null
+++ b/java/net/ProtocolException.java
@@ -0,0 +1,62 @@
+/*************************************************************************
+/* ProtocolException.java -- A low level protocol error occuredA low level protocol error occured
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This exception indicates that some sort of low level protocol
+ * exception occured. Look in the descriptive message (if any) for
+ * details on what went wrong
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class ProtocolException extends java.io.IOException
+{
+
+/*
+ * Constructors
+ */
+
+/**
+ * Constructs a new ProtocolException with no descriptive message.
+ */
+public
+ProtocolException()
+{
+ super();
+}
+
+/*************************************************************************/
+
+/**
+ * Constructs a new ProtocolException with a descriptive message (such as the
+ * text from strerror(3)) passed in as an argument
+ *
+ * @param message A message describing the error that occurs
+ */
+public
+ProtocolException(String message)
+{
+ super(message);
+}
+
+} // class ProtocolException
+
diff --git a/java/net/STATUS b/java/net/STATUS
new file mode 100644
index 000000000..25dff963e
--- /dev/null
+++ b/java/net/STATUS
@@ -0,0 +1,48 @@
+X ContentHandlerFactory
+X FileNameMap
+X SocketImplFactory
+X URLStreamHandlerFactory
+* Authenticator
+* ContentHandler
++ DatagramPacket
++ DatagramSocket
++ DatagramSocketImpl
++ HttpURLConnection
++ InetAddress
+* JarURLConnection
++ MulticastSocket
+* NetPermission
+* PasswordAuthentication
++ PlainDatagramSocketImpl
++ PlainSocketImpl (internal)
++ ServerSocket
++ Socket
++ SocketImpl
++ SocketInputStream (internal)
++ SocketOptions (internal)
++ SocketOutputStream (internal)
+* SocketPermission
++ URL
+ URLClassLoader
++ URLConnection
+* URLEncoder
++ URLStreamHandler
+X BindException
+X ConnectException
+X MalformedURLException
+X NoRouteToHostException
+X ProtocolException
+X SocketException
+X UnknownHostException
+X UnknownServiceException
+
+---------------
++ Native InetAddress
++ Native SocketImpl
++ Native DatagramSocketImpl
++ Protocol Handler for HTTP
+ Protocol Handler for FTP
++ ContentHandler for text
+ ContentHandler for gif
+ ContentHandler for jpeg
+
diff --git a/java/net/ServerSocket.java b/java/net/ServerSocket.java
new file mode 100644
index 000000000..1c4a0d4d8
--- /dev/null
+++ b/java/net/ServerSocket.java
@@ -0,0 +1,324 @@
+/*************************************************************************
+/* ServerSocket.java -- Class for implementing server side sockets
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.IOException;
+//import java.security.AccessControlException;
+
+/**
+ * This class models server side sockets. The basic model is that the
+ * server socket is created and bound to some well known port. It then
+ * listens for and accepts connections. At that point the client and
+ * server sockets are ready to communicate with one another utilizing
+ * whatever application layer protocol they desire.
+ * <p>
+ * As with the Socket class, most instance methods of this class simply
+ * redirect their calls to an implementation class.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class ServerSocket
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
+ */
+
+/**
+ * This is the user defined SocketImplFactory, if one is supplied
+ */
+protected static SocketImplFactory factory;
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * This is the SocketImp object to which most instance methods in this
+ * class are redirected
+ */
+protected SocketImpl impl;
+
+/*************************************************************************/
+
+/**
+ * Since the implementation doesn't directly store this value, we keep
+ * it here. This is the local address we are bound to.
+ */
+InetAddress addr;
+
+/*************************************************************************/
+
+/*
+ * Class methods
+ */
+
+/**
+ * Sets the SocketImplFactory for all ServerSockets. This may only be done
+ * once per virtual machine. Subsequent attempts will generate a
+ * SocketException. Note that a SecurityManager check is made prior to
+ * setting the factory. If insufficient privileges exist to set the factory,
+ * an IOException will be thrown
+ *
+ * @exception SocketException If the factory object is already defined
+ * @exception IOException If any other error occurs
+ */
+public static synchronized void
+setSocketFactory(SocketImplFactory factory) throws IOException
+{
+ // See if already set
+ if (ServerSocket.factory != null)
+ throw new SocketException("SocketImplFactory already defined");
+
+ // Check permission to perform this operation
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ try
+ {
+ sm.checkSetFactory();
+ }
+// catch (AccessControlException e)
+ catch (SecurityException e)
+ {
+ throw new IOException(e.toString());
+ }
+ }
+
+ ServerSocket.factory = factory;
+}
+
+/*************************************************************************/
+
+/**
+ * This protected constructor is used by subclasses of ServerSocket. It
+ * simply load the implementation and returns
+ */
+protected
+ServerSocket()
+{
+ if (factory != null)
+ impl = factory.createSocketImpl();
+ else
+ impl = new PlainSocketImpl();
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a server socket and binds it to the specified port. If the
+ * port number is 0, a random free port will be chosen. The pending
+ * connection queue on this socket will be set to 50.
+ *
+ * @param port The port number to bind to
+ *
+ * @exception IOException If an error occurs
+ */
+public
+ServerSocket(int port) throws IOException
+{
+ this(port, 50, InetAddress.getInaddrAny());
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a server socket and binds it to the specified port. If the
+ * port number is 0, a random free port will be chosen. The pending
+ * connection queue on this socket will be set to the value passed as
+ * arg2.
+ *
+ * @param port The port number to bind to
+ * @param queuelen The length of the pending connection queue
+ *
+ * @exception IOException If an error occurs
+ */
+public
+ServerSocket(int port, int queuelen) throws IOException
+{
+ this(port, queuelen, InetAddress.getInaddrAny());
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a server socket and binds it to the specified port. If the
+ * port number is 0, a random free port will be chosen. The pending
+ * connection queue on this socket will be set to the value passed as
+ * arg2. The third argument specifies a particular local address to
+ * bind to.
+ *
+ * @param port The port number to bind to
+ * @param queuelen The length of the pending connection queue
+ * @param addr The address to bind to
+ *
+ * @exception IOException If an error occurs
+ */
+public
+ServerSocket(int port, int queuelen, InetAddress addr) throws IOException
+{
+ this();
+ if (impl == null)
+ throw new IOException("Cannot initialize Socket implementation");
+
+ impl.create(true);
+ impl.bind(addr, port);
+ this.addr = addr;
+ impl.listen(queuelen);
+
+}
+
+/*************************************************************************/
+
+/**
+ * This protected method is used to help subclasses override
+ * ServerSocket.accept(). The passed in Socket will be connected when
+ * this method returns.
+ *
+ * @param socket The Socket that is used for the accepted connection
+ *
+ * @exception IOException If an error occurs
+ */
+protected final synchronized void
+implAccept(Socket socket) throws IOException
+{
+ impl.accept(socket.impl);
+}
+
+/*************************************************************************/
+
+/**
+ * Accepts a new connection and returns a connected Socket instance
+ * representing that connection. This method will block until a
+ * connection is available.
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized Socket
+accept() throws IOException
+{
+ Socket socket = new Socket();
+ impl.accept(socket.impl);
+
+ return(socket);
+}
+
+/*************************************************************************/
+
+/**
+ * Closes this socket and stops listening for connections
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+close() throws IOException
+{
+ impl.close();
+}
+
+/*************************************************************************/
+
+/**
+ * This method returns the local address to which this socket is bound
+ *
+ * @return The socket's local address
+ */
+public InetAddress
+getInetAddress()
+{
+ return(addr);
+}
+
+/*************************************************************************/
+
+/**
+ * This method returns the local port number to which this socket is bound
+ *
+ * @return The socket's port number
+ */
+public int
+getLocalPort()
+{
+ return(impl.getLocalPort());
+}
+
+/*************************************************************************/
+
+/**
+ * Retrieves the current value of the SO_TIMEOUT setting. A value of 0
+ * implies that SO_TIMEOUT is disabled (ie, operations never time out).
+ * This is the number of milliseconds a socket operation can block before
+ * an InterruptedIOException is thrown.
+ *
+ * @return The value of SO_TIMEOUT
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized int
+getSoTimeout() throws IOException
+{
+ Object obj = impl.getOption(SocketOptions.SO_TIMEOUT);
+
+ if (!(obj instanceof Integer))
+ throw new IOException("Internal Error");
+
+ return(((Integer)obj).intValue());
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the value of SO_TIMEOUT. A value of 0 implies that SO_TIMEOUT is
+ * disabled (ie, operations never time out). This is the number of
+ * milliseconds a socket operation can block before an
+ * InterruptedIOException is thrown.
+ *
+ * @param timeout The new SO_TIMEOUT value
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+setSoTimeout(int timeout) throws IOException
+{
+ impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of this ServerSocket as a String. Overrides
+ * Object.toString()
+ *
+ * @return This socket represented as a String
+ */
+public String
+toString()
+{
+ return(addr + ":" + getLocalPort());
+}
+
+} // class ServerSocket
+
diff --git a/java/net/Socket.java b/java/net/Socket.java
new file mode 100644
index 000000000..6708232e9
--- /dev/null
+++ b/java/net/Socket.java
@@ -0,0 +1,591 @@
+/*************************************************************************
+/* Socket.java -- Client socket implementation
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.*;
+import java.security.*;
+
+/**
+ * This class models a client site socket. A socket is a TCP/IP endpoint
+ * for network communications conceptually similar to a file handle.
+ * <p>
+ * This class does not actually do any work. Instead, it redirects all of
+ * its calls to a socket implementation object which implements the
+ * SocketImpl interface. The implementation class is instantiated by
+ * factory class that implements the SocketImplFactory interface. A default
+ * factory is provided, however the factory may be set by a call to
+ * the setSocketImplFactory method. Note that this may only be done once
+ * per virtual machine. If a subsequent attempt is made to set the
+ * factory, a SocketException will be thrown.
+ *
+ * @version
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class Socket
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
+ */
+
+/**
+ * This is the user SocketImplFactory for this class. If this variable is
+ * null, a default factory is used.
+ */
+protected static SocketImplFactory factory;
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The implementation object to which calls are redirected
+ */
+protected SocketImpl impl;
+
+/**
+ * The local address to which we are connected
+ */
+InetAddress local_addr;
+
+/*************************************************************************/
+
+/*
+ * Class Methods
+ */
+
+/**
+ * Sets the SocketImplFactory. This may be done only once per virtual
+ * machine. Subsequent attempts will generate a SocketException. Note that
+ * a SecurityManager check is made prior to setting the factory. If
+ * insufficient privileges exist to set the factory, then an IOException
+ * will be thrown.
+ *
+ * @exception SocketException If the SocketImplFactory is already defined
+ * @exception IOException If any other error occurs
+ */
+public static synchronized void
+setSocketImplFactory(SocketImplFactory factory) throws IOException
+{
+ // See if already set
+ if (Socket.factory != null)
+ throw new SocketException("SocketImplFactory already defined");
+
+ // Check permissions
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ try
+ {
+ sm.checkSetFactory();
+ }
+// catch (AccessControlException e)
+ catch (SecurityException e)
+ {
+ throw new IOException(e.toString());
+ }
+ }
+
+ Socket.factory = factory;
+}
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * This creates a Socket object without connecting to a remote host. This
+ * useful for subclasses of socket that might want this behavior.
+ */
+protected
+Socket()
+{
+ if (factory != null)
+ impl = factory.createSocketImpl();
+ else
+ impl = new PlainSocketImpl();
+}
+
+/*************************************************************************/
+
+/**
+ * This creates a Socket object without connecting to a remote host. This
+ * is useful for subclasses of socket that might want this behavior.
+ * Additionally, this socket will be created using the supplied implementation
+ * class instead the default class or one returned by a factory. This
+ * value can be null, but if it is, all instance methods in Socket should
+ * be overridden because most of them rely on this value being populated.
+ *
+ * @param impl The SocketImpl to use for this Socket
+ *
+ * @exception SocketException If an error occurs
+ */
+protected
+Socket(SocketImpl impl) throws SocketException
+{
+ this.impl = impl;
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a Socket and connects to the address and port number specified
+ * as arguments.
+ *
+ * @param add The address to connect to
+ * @param port The port number to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+public
+Socket(InetAddress addr, int port) throws IOException
+{
+ this(addr, port, InetAddress.getInaddrAny(), 0, true);
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a Socket and connects to the address and port number specified
+ * as arguments. If the stream param is true, a stream socket will be
+ * created, otherwise a datagram socket is created.
+ * <p>
+ * <b>This method is deprecated. Use the DatagramSocket class for creating
+ * datagram sockets.</b>
+ *
+ * @param add The address to connect to
+ * @param port The port number to connect to
+ * @param stream True to create a stream socket, false to create a datagram socket
+ *
+ * @exception IOException If an error occurs
+ *
+ * @deprecated
+ */
+public
+Socket(InetAddress addr, int port, boolean stream) throws IOException
+{
+ this(addr, port, InetAddress.getInaddrAny(), 0, stream);
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a Socket and connects to the address and port number specified
+ * as arguments, plus binds to the specified local address and port.
+ *
+ * @param raddr The remote address to connect to
+ * @param rport The remote port to connect to
+ * @param laddr The local address to connect to
+ * @param lport The local port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+public
+Socket(InetAddress raddr, int rport, InetAddress laddr,
+ int lport) throws IOException
+{
+ this(raddr, rport, laddr, lport, true);
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a Socket and connects to the hostname and port specified as
+ * arguments.
+ *
+ * @param hostname The name of the host to connect to
+ * @param port The port number to connect to
+ *
+ * @exception UnknownHostException If the hostname cannot be resolved to an address
+ * @exception IOException If an error occurs
+ */
+public
+Socket(String hostname, int port) throws IOException
+{
+ this(InetAddress.getByName(hostname), port, InetAddress.getInaddrAny(),
+ 0, true);
+}
+
+/*************************************************************************/
+
+/**
+ * Creates a Socket and connects to the hostname and port specified as
+ * arguments. If the stream argument is set to true, then a stream socket
+ * is created. If it is false, a datagram socket is created.
+ * <p>
+ * <b>This method is deprecated. Use the DatagramSocket class to create
+ * datagram oriented sockets.</b>
+ *
+ * @param hostname The name of the host to connect to
+ * @param port The port to connect to
+ * @param stream true for a stream socket, false for a datagram socket
+ *
+ * @exception IOException If an error occurs
+ */
+public
+Socket(String hostname, int port, boolean stream) throws IOException
+{
+ this(InetAddress.getByName(hostname), port, InetAddress.getInaddrAny(),
+ 0, stream);
+}
+
+/*************************************************************************/
+
+/**
+ * This constructor is where the real work takes place. Connect to the
+ * specified address and port. Use default local values if not specified,
+ * otherwise use the local host and port passed in. Create as stream or
+ * datagram based on "stream" argument.
+ * <p>
+ * ******* Check security *************
+ *
+ * @param raddr The remote address to connect to
+ * @param rport The remote port to connect to
+ * @param laddr The local address to connect to
+ * @param lport The local port to connect to
+ * @param stream true for a stream socket, false for a datagram socket
+ *
+ * @exception IOException If an error occurs
+ */
+private
+Socket(InetAddress raddr, int rport, InetAddress laddr, int lport,
+ boolean stream) throws IOException
+{
+ this();
+ if (impl == null)
+ throw new IOException("Cannot initialize Socket implementation");
+
+ impl.create(stream);
+
+ if (laddr != null)
+ impl.bind(laddr, lport);
+
+ local_addr = laddr;
+
+ if (raddr != null)
+ impl.connect(raddr, rport);
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * Closes the socket.
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+close() throws IOException
+{
+ if (impl != null)
+ impl.close();
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the address of the remote end of the socket. If this socket
+ * is not connected, then ???
+ *
+ * @return The remote address this socket is connected to
+ */
+public InetAddress
+getInetAddress()
+{
+ if (impl != null)
+ return(impl.getInetAddress());
+
+ return(null);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the port number of the remote end of the socket connection. If
+ * this socket is not connected, then ???
+ *
+ * @return The remote port this socket is connected to
+ */
+public int
+getPort()
+{
+ if (impl != null)
+ return(impl.getPort());
+
+ return(-1);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the local address to which this socket is bound. If this socket
+ * is not connected, then ???
+ *
+ * @return The local address
+ */
+public InetAddress
+getLocalAddress()
+{
+ return(local_addr);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the local port number to which this socket is bound. If this
+ * socket is not connected, then ???
+ *
+ * @return The local port
+ */
+public int
+getLocalPort()
+{
+ if (impl != null)
+ return(impl.getLocalPort());
+
+ return(-1);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an InputStream for reading from this socket.
+ *
+ * @return The InputStream object
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized InputStream
+getInputStream() throws IOException
+{
+ if (impl != null)
+ return(impl.getInputStream());
+
+ throw new IOException("Not connected");
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an OutputStream for writing to this socket.
+ *
+ * @return The OutputStream object
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized OutputStream
+getOutputStream() throws IOException
+{
+ if (impl != null)
+ return(impl.getOutputStream());
+
+ throw new IOException("Not connected");
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the SO_LINGER option on the socket. If the
+ * SO_LINGER option is set on a socket and there is still data waiting to
+ * be sent when the socket is closed, then the close operation will block
+ * until either that data is delivered or until the timeout period
+ * expires. This method either returns the timeouts (in hundredths of
+ * of a second (****????****)) if SO_LINGER is set, or -1 if SO_LINGER is
+ * not set.
+ *
+ * @return The SO_LINGER timeout in hundreths of a second or -1 if SO_LINGER not set
+ *
+ * @exception SocketException If an error occurs
+ */
+public synchronized int
+getSoLinger() throws SocketException
+{
+ if (impl == null)
+ throw new SocketException("Not connected");
+
+ Object obj = impl.getOption(SocketOptions.SO_LINGER);
+
+ if (obj instanceof Boolean)
+ return(-1); // Boolean is only returned in unset case
+
+ if (obj instanceof Integer)
+ return(((Integer)obj).intValue());
+ else
+ throw new SocketException("Internal Error");
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the value of the SO_LINGER option on the socket. If the
+ * SO_LINGER option is set on a socket and there is still data waiting to
+ * be sent when the socket is closed, then the close operation will block
+ * until either that data is delivered or until the timeout period
+ * expires. The linger interval is specified in hundreths of a second
+ * *********???????********
+ *
+ * @param state true to enable SO_LINGER, false to disable
+ * @param timeout The SO_LINGER timeout in hundreths of a second or -1 if SO_LINGER not set
+ *
+ * @exception SocketException If an error occurs
+ */
+public synchronized void
+setSoLinger(boolean state, int timeout) throws SocketException
+{
+ if (impl == null)
+ throw new SocketException("No socket created");
+
+ if (state == true)
+ impl.setOption(SocketOptions.SO_LINGER, new Integer(timeout));
+ else
+ impl.setOption(SocketOptions.SO_LINGER, new Boolean(false));
+
+ return;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the SO_TIMEOUT option on the socket. If this value
+ * is set, and an read/write is performed that does not complete within
+ * the timeout period, a short count is returned (or an EWOULDBLOCK signal
+ * would be sent in Unix if no data had been read). A value of 0 for
+ * this option implies that there is no timeout (ie, operations will
+ * block forever). On systems that have separate read and write timeout
+ * values, this method returns the read timeout. This
+ * value is in thousandths of a second. (*****Is it *******);
+ *
+ * @return The length of the timeout in thousandth's of a second or 0 if not set
+ *
+ * @exception SocketException If an error occurs
+ */
+public synchronized int
+getSoTimeout() throws SocketException
+{
+ if (impl == null)
+ throw new SocketException("Not connected");
+
+ Object obj = impl.getOption(SocketOptions.SO_TIMEOUT);
+
+ if (obj instanceof Integer)
+ return(((Integer)obj).intValue());
+ else
+ throw new SocketException("Internal Error");
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the value of the SO_TIMEOUT option on the socket. If this value
+ * is set, and an read/write is performed that does not complete within
+ * the timeout period, a short count is returned (or an EWOULDBLOCK signal
+ * would be sent in Unix if no data had been read). A value of 0 for
+ * this option implies that there is no timeout (ie, operations will
+ * block forever). On systems that have separate read and write timeout
+ * values, this method returns the read timeout. This
+ * value is in thousandths of a second (****????*****)
+ *
+ * @param timeout The length of the timeout in thousandth's of a second or 0 if not set
+ *
+ * @exception SocketException If an error occurs
+ */
+public synchronized void
+setSoTimeout(int timeout) throws SocketException
+{
+ if (impl == null)
+ throw new SocketException("Not connected");
+
+ impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+
+ return;
+}
+
+/*************************************************************************/
+
+/**
+ * Tests whether or not the TCP_NODELAY option is set on the socket.
+ * Returns true if enabled, false if disabled. *** Need good explanation
+ * of this parameter.
+ *
+ * @return Whether or not TCP_NODELAY is set
+ *
+ * @exception SocketException If an error occurs
+ */
+public synchronized boolean
+getTcpNoDelay() throws SocketException
+{
+ if (impl == null)
+ throw new SocketException("Not connected");
+
+ Object obj = impl.getOption(SocketOptions.TCP_NODELAY);
+
+ if (obj instanceof Boolean)
+ return(((Boolean)obj).booleanValue());
+ else
+ throw new SocketException("Internal Error");
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the TCP_NODELAY option is set on the socket.
+ * Returns true if enabled, false if disabled. *** Need good explanation
+ * of this parameter.
+ *
+ * @param state true to enable, false to disable
+ *
+ * @exception SocketException If an error occurs
+ */
+public synchronized void
+setTcpNoDelay(boolean state) throws SocketException
+{
+ if (impl == null)
+ throw new SocketException("Not connected");
+
+ impl.setOption(SocketOptions.TCP_NODELAY, new Boolean(state));
+
+ return;
+}
+
+/*************************************************************************/
+
+/**
+ * Converts this Socket to a String. Overrides Object.toString()
+ *
+ * @return The String representation of this Socket
+ */
+public String
+toString()
+{
+ return(getInetAddress().getHostName() + ":" + getPort());
+}
+
+} // class Socket
+
diff --git a/java/net/SocketException.java b/java/net/SocketException.java
new file mode 100644
index 000000000..360eef28d
--- /dev/null
+++ b/java/net/SocketException.java
@@ -0,0 +1,62 @@
+/*************************************************************************
+/* SocketException.java -- An exception occured while performing a socket op
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This exception indicates that a generic error occured related to an
+ * operation on a socket. Check the descriptive message (if any) for
+ * details on the nature of this error
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class SocketException extends java.io.IOException
+{
+
+/*
+ * Constructors
+ */
+
+/**
+ * Constructs a new SocketException with no descriptive message.
+ */
+public
+SocketException()
+{
+ super();
+}
+
+/*************************************************************************/
+
+/**
+ * Constructs a new SocketException with a descriptive message (such as the
+ * text from strerror(3)) passed in as an argument
+ *
+ * @param message A message describing the error that occurs
+ */
+public
+SocketException(String message)
+{
+ super(message);
+}
+
+} // class SocketException
+
diff --git a/java/net/SocketImpl.java b/java/net/SocketImpl.java
new file mode 100644
index 000000000..e0f87ce62
--- /dev/null
+++ b/java/net/SocketImpl.java
@@ -0,0 +1,295 @@
+/*************************************************************************
+/* SocketImpl.java -- Abstract socket implementation class
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.*;
+
+/**
+ * This abstract class serves as the parent class for socket implementations.
+ * The implementation class serves an intermediary to native routines that
+ * perform system specific socket operations.
+ * <p>
+ * A default implementation is provided by the system, but this can be
+ * changed via installing a SocketImplFactory (through a call to the
+ * static method Socket.setSocketImplFactory). A subclass of Socket can
+ * also pass in a SocketImpl to the Socket(SocketImpl) constructor to
+ * use an implementation different from the system default without installing
+ * a factory.
+ * <p>
+ * Note that the SocketOptions interface is protected. It contains the
+ * declaration of the methods getOption and setOption (***???***) that are
+ * used by Socket() for setting various options on the socket. This is
+ * of interest only to implementors.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract class SocketImpl implements SocketOptions
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
+ */
+
+/**
+ * The address of the remote end of the socket connection
+ */
+protected InetAddress address;
+
+/**
+ * The port number of the remote end of the socket connection
+ */
+protected int port;
+
+/**
+ * The port number the socket is bound to locally
+ */
+protected int localport;
+
+/**
+ * A FileDescriptor object representing this socket connection.
+ * ***** How do I create one of these? ********
+ */
+protected FileDescriptor fd;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * A do nothing default public construtor
+ */
+public
+SocketImpl()
+{
+ ;
+}
+
+/*************************************************************************/
+
+/**
+ * Accepts a connection on this socket.
+ *
+ * @param impl The implementation object for the accepted connection.
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+accept(SocketImpl impl) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Returns the number of bytes that the caller can read from this socket
+ * without blocking.
+ *
+ * @return The number of readable bytes before blocking
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized int
+available() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Binds to the specified port on the specified addr. Note that this addr
+ * must represent a local IP address. **** How bind to INADDR_ANY? ****
+ *
+ * @param addr The address to bind to
+ * @param port The port number to bind to
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+bind(InetAddress addr, int port) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Closes the socket. This will cause any InputStream or OutputStream
+ * objects for this Socket to be closed as well ******* Will it? *********
+ * <p>
+ * Note that if the SO_LINGER option is set on this socket, then the
+ * operation could block.
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+close() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Connects to the remote address and port specified as arguments.
+ *
+ * @param addr The remote address to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+connect(InetAddress addr, int port) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Connects to the remote hostname and port specified as arguments.
+ *
+ * @param hostname The remote hostname to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+connect(String hostname, int port) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Creates a new socket that is not bound to any local address/port and
+ * is not connected to any remote address/port. This will be created as
+ * a stream socket if the stream parameter is true, or a datagram socket
+ * if the stream parameter is false.
+ *
+ * @param stream true for a stream socket, false for a datagram socket
+ */
+protected abstract void
+create(boolean stream) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Returns the FileDescriptor objects for this socket.
+ *
+ * @return A FileDescriptor for this socket.
+ */
+protected FileDescriptor
+getFileDescriptor()
+{
+ return(fd);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the local port this socket is bound to
+ *
+ * @return The local port
+ */
+protected int
+getLocalPort()
+{
+ return(localport);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the remote address this socket is connected to
+ *
+ * @return The remote address
+ */
+protected InetAddress
+getInetAddress()
+{
+ return(address);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the remote port this socket is connected to
+ *
+ * @return The remote port
+ */
+protected int
+getPort()
+{
+ return(port);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an InputStream object for reading from this socket
+ *
+ * @return An InputStream
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized InputStream
+getInputStream() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Returns an OutputStream object for writing to this socket
+ *
+ * @return An OutputStream
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized OutputStream
+getOutputStream() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Starts listening for connections on a socket. The queuelen parameter
+ * is how many pending connections will queue up waiting to be serviced
+ * before being accept'ed. If the queue of pending requests exceeds this
+ * number, additional connections will be refused.
+ *
+ * @param queuelen The length of the pending connection queue
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized void
+listen(int queuelen) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Returns a String representing the remote host and port of this
+ * socket.
+ */
+public String
+toString()
+{
+ StringBuffer sb = new StringBuffer("");
+
+ if (address == null)
+ sb.append("<null>:");
+ else
+ sb.append(address.getHostAddress() + ":");
+
+ sb.append(port);
+
+ return(sb.toString());
+}
+
+} // class SocketImpl
+
diff --git a/java/net/SocketImplFactory.java b/java/net/SocketImplFactory.java
new file mode 100644
index 000000000..81d575fb2
--- /dev/null
+++ b/java/net/SocketImplFactory.java
@@ -0,0 +1,40 @@
+/*************************************************************************
+/* SocketImplFactory.java -- Interface to create a SocketImpl object
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This interface defines one method which returns a SocketImpl object.
+ * This should not be needed by ordinary applications.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public interface SocketImplFactory
+{
+/**
+ * This method returns an instance of the SocketImpl object
+ *
+ * @return A SocketImpl object
+ */
+public abstract SocketImpl
+createSocketImpl();
+
+} // interface SocketImplFactory
diff --git a/java/net/SocketInputStream.java b/java/net/SocketInputStream.java
new file mode 100644
index 000000000..2d16be06f
--- /dev/null
+++ b/java/net/SocketInputStream.java
@@ -0,0 +1,189 @@
+/*************************************************************************
+/* SocketInputStream.java -- An InputStream for Sockets
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This class contains an implementation of InputStream for sockets. It
+ * in an internal only class used by PlainSocketImpl.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+class SocketInputStream extends InputStream
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The PlainSocketImpl object this stream is associated with
+ */
+protected PlainSocketImpl impl;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Builds an instance of this class from a PlainSocketImpl object
+ */
+protected
+SocketInputStream(PlainSocketImpl impl)
+{
+ this.impl = impl;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * Returns the number of bytes available to be read before blocking
+ */
+public int
+available() throws IOException
+{
+ return(impl.available());
+}
+
+/*************************************************************************/
+
+/**
+ * Determines if "mark" functionality is supported on this stream. For
+ * sockets, this is always false. Note that the superclass default is
+ * false, but it is overridden out of safety concerns and/or paranoia.
+ */
+public boolean
+markSupported()
+{
+ return(false);
+}
+
+/*************************************************************************/
+
+/**
+ * Do nothing mark method since we don't support this functionality. Again,
+ * overriding out of paranoia.
+ *
+ * @param readlimit In theory, the number of bytes we can read before the mark becomes invalid
+ */
+public void
+mark(int readlimit)
+{
+ ;
+}
+
+/*************************************************************************/
+
+/**
+ * Since we don't support mark, this method always throws an exception
+ *
+ * @exception IOException Everytime since we don't support this functionality
+ */
+public void
+reset() throws IOException
+{
+ throw new IOException("Socket InputStreams do not support mark/reset");
+}
+
+/*************************************************************************/
+
+/**
+ * This method not only closes the stream, it closes the underlying socket
+ * (and thus any connection) and invalidates any other Input/Output streams
+ * for the underlying impl object
+ */
+public void
+close() throws IOException
+{
+ impl.close();
+}
+
+/*************************************************************************/
+
+/**
+ * Reads the next byte of data and returns it as an int.
+ *
+ * @return The byte read (as an int) or -1 if end of stream);
+ *
+ * @exception IOException If an error occurs.
+ */
+public int
+read() throws IOException
+{
+ byte buf[] = new byte[1];
+
+ int bytes_read = read(buf, 0, buf.length);
+
+ if (bytes_read != -1)
+ return((int)buf[0]);
+ else
+ return(-1);
+}
+
+/*************************************************************************/
+
+/**
+ * Reads up to buf.length bytes of data into the caller supplied buffer.
+ *
+ * @return The actual number of bytes read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs.
+ */
+public int
+read(byte[] buf) throws IOException
+{
+ int bytes = read(buf, 0, buf.length);
+
+ if (bytes == 0)
+ bytes = -1;
+
+ return(bytes);
+}
+
+/*************************************************************************/
+
+/**
+ * Reads up to len bytes of data into the caller supplied buffer starting
+ * at offset bytes from the start of the buffer
+ *
+ * @return The number of bytes actually read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs.
+ */
+public int
+read(byte[] buf, int offset, int len) throws IOException
+{
+ return(impl.read(buf, offset, len));
+}
+
+} // class SocketInputStream
+
diff --git a/java/net/SocketOptions.java b/java/net/SocketOptions.java
new file mode 100644
index 000000000..a4d701217
--- /dev/null
+++ b/java/net/SocketOptions.java
@@ -0,0 +1,108 @@
+/*************************************************************************
+/* SocketOptions.java -- Implements options for sockets (duh!)
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This internal interface is used by SocketImpl to implement options
+ * on sockets. At least I think. The javadocs for SocketImpl show it
+ * implementing this interface and the Networking Enhancements description
+ * for Java 1.1 show two methods that aren't in the public javadocs, so
+ * I'll assume this is where they live.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+interface SocketOptions
+{
+
+/*************************************************************************/
+
+/*
+ * Static Variables
+ */
+
+// Note that these contant values were determined by experimentation and
+// there is no way to currently know if the symbolic names are the
+// same as in the JDK.
+
+/**
+ * Option id for the SO_LINGER value
+ */
+static final int SO_LINGER = 128;
+
+/**
+ * Option id for the SO_TIMEOUT value
+ */
+static final int SO_TIMEOUT = 4102;
+
+/**
+ * Option id for the TCP_NODELAY value
+ */
+static final int TCP_NODELAY = 1;
+
+/**
+ * Option id for the IP_TTL (time to live) value.
+ */
+static final int IP_TTL = 7777;
+
+/**
+ * Options id for the IP_MULTICAST_IF value
+ */
+static final int IP_MULTICAST_IF = 7778;
+
+/*************************************************************************/
+
+/*
+ * Interface Methods
+ */
+
+/**
+ * Sets the specified option on a socket to the passed in object. For
+ * options that take an integer argument, the passed in object is an
+ * Integer. The option_id parameter is one of the defined constants in
+ * this interface.
+ *
+ * @param option_id The identifier of the option
+ * @param val The value to set the option to
+ *
+ * @exception SocketException If an error occurs
+ */
+abstract void
+setOption(int option_id, Object val) throws SocketException;
+
+/*************************************************************************/
+
+/**
+ * Returns the current setting of the specified option. The Object returned
+ * will be an Integer for options that have integer values. The option_id
+ * is one of the defined constants in this interface.
+ *
+ * @param option_id The option identifier
+ *
+ * @return The current value of the option
+ *
+ * @exception SocketException If an error occurs
+ */
+abstract Object
+getOption(int option_id) throws SocketException;
+
+} // interface SocketOptions
+
diff --git a/java/net/SocketOutputStream.java b/java/net/SocketOutputStream.java
new file mode 100644
index 000000000..4b07d6d71
--- /dev/null
+++ b/java/net/SocketOutputStream.java
@@ -0,0 +1,148 @@
+/*************************************************************************
+/* SocketOutputStream.java -- OutputStream for PlainSocketImpl
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This class is used internally by PlainSocketImpl to be the OutputStream
+ * subclass returned by its getOutputStream method. It expects only to
+ * be used in that context.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+class SocketOutputStream extends OutputStream
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The PlainSocketImpl object this stream is associated with
+ */
+protected PlainSocketImpl impl;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Build an instance of this class from a PlainSocketImpl object
+ */
+protected
+SocketOutputStream(PlainSocketImpl impl)
+{
+ this.impl = impl;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * This method closes the stream and the underlying socket connection. This
+ * action also effectively closes any other InputStream or OutputStream
+ * object associated with the connection.
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+close() throws IOException
+{
+ impl.close();
+}
+
+/*************************************************************************/
+
+/**
+ * Hmmm, we don't seem to have a flush() method in Socket impl, so just
+ * return for now, but this might need to be looked at later.
+ *
+ * @exception IOException Can't happen
+ */
+public void
+flush() throws IOException
+{
+ return;
+}
+
+/*************************************************************************/
+
+/**
+ * Writes a byte (passed in as an int) to the given output stream
+ *
+ * @param b The byte to write
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+write(int b) throws IOException
+{
+ byte buf[] = new byte[1];
+
+ Integer i = new Integer(b);
+ buf[0] = i.byteValue();
+
+ write(buf, 0, buf.length);
+}
+
+/*************************************************************************/
+
+/**
+ * Write an array of bytes to the output stream
+ *
+ * @param buf The array of bytes to write
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+write(byte[] buf) throws IOException
+{
+ write(buf, 0, buf.length);
+}
+
+/*************************************************************************/
+
+/**
+ * Writes len number of bytes from the array buf to the stream starting
+ * at offset bytes into the buffer.
+ *
+ * @param buf The buffer
+ * @param offset Offset into the buffer to start writing from
+ * @param len The number of bytes to write
+ */
+public void
+write(byte[] buf, int offset, int len) throws IOException
+{
+ impl.write(buf, offset, len);
+}
+
+} // class SocketOutputStream
+
diff --git a/java/net/SocketPermission.java b/java/net/SocketPermission.java
new file mode 100644
index 000000000..068c56c11
--- /dev/null
+++ b/java/net/SocketPermission.java
@@ -0,0 +1,380 @@
+/*************************************************************************
+/* SocketPermission.java -- Class modeling permissions for socket operations
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.security.Permission;
+import java.security.PermissionCollection;
+
+/**
+ * This class models a specific set of permssions for connecting to a
+ * host. There are two elements to this, the host/port combination and
+ * the permission list.
+ * <p>
+ * The host/port combination is specified as followed
+ * <p>
+ * <pre>
+ * hostname[:[-]port[-[port]]]
+ * </pre>
+ * <p>
+ * The hostname portion can be either a hostname or IP address. If it is
+ * a hostname, a wildcard is allowed in hostnames. This wildcard is a "*"
+ * and matches one or more characters. Only one "*" may appear in the
+ * host and it must be the leftmost character. For example,
+ * "*.urbanophile.com" matches all hosts in the "urbanophile.com" domain.
+ * <p>
+ * The port portion can be either a single value, or a range of values
+ * treated as inclusive. The first or the last port value in the range
+ * can be omitted in which case either the minimum or maximum legal
+ * value for a port (respectively) is used by default. Here are some
+ * examples:
+ * <p><ul>
+ * <li>8080 - Represents port 8080 only
+ * <li>2000-3000 - Represents ports 2000 through 3000 inclusive
+ * <li>-4000 - Represents ports 0 through 4000 inclusive
+ * <li>1024- - Represents ports 1024 through 65535 inclusive
+ * </ul><p>
+ * The permission list is a comma separated list of individual permissions.
+ * These individual permissions are:
+ * <p>
+ * accept<br>
+ * connect<br>
+ * listen<br>
+ * resolve<br>
+ * <p>
+ * The "listen" permission is only relevant if the host is localhost. If
+ * any permission at all is specified, then resolve permission is implied to
+ * exist.
+ * <p>
+ * Here are a variety of examples of how to create SocketPermission's
+ * <p><pre>
+ * SocketPermission("www.urbanophile.com", "connect");
+ * Can connect to any port on www.urbanophile.com
+ * SocketPermission("www.urbanophile.com:80", "connect,accept");
+ * Can connect to or accept connections from www.urbanophile.com on port 80
+ * SocketPermission("localhost:1024-", "listen,accept,connect");
+ * Can connect to, accept from, an listen on any local port number 1024 and up.
+ * SocketPermission("*.edu", "connect");
+ * Can connect to any host in the edu domain
+ * SocketPermission("197.197.20.1", "accept");
+ * Can accept connections from 197.197.20.1
+ * </pre><p>
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public final class SocketPermission extends Permission
+{
+
+/*************************************************************************/
+
+/**
+ * Instance Variables
+ */
+
+/**
+ * A hostname/port combination as described above
+ */
+protected String hostport;
+
+/**
+ * A comma separated list of actions for which we have permission
+ */
+protected String perms;
+
+/*************************************************************************/
+
+/**
+ * Creates a SocketPermission with the specified host/port combination
+ * and permissions string.
+ *
+ * @param hostport The hostname/port number combination
+ * @param perms The permissions string
+ */
+public
+SocketPermission(String hostport, String perms)
+{
+ super(hostport);
+
+ this.hostport = hostport;
+ this.perms = perms;
+}
+
+/*************************************************************************/
+
+/**
+ * Tests this object for equality against another. This will be true if
+ * and only if the passed object is an instance of SocketPermission and
+ * both its hostname/port combination and permissions string are
+ * identical. Overrides Permission.equals()
+ *
+ * @param obj The object to test against for equality
+ *
+ * @return true if object is equal to this object, false otherwise
+ */
+public boolean
+equals(Object obj)
+{
+ if (!(obj instanceof SocketPermission))
+ return(false);
+
+ if (((SocketPermission)obj).hostport.equals(hostport))
+ if (((SocketPermission)obj).perms.equals(perms))
+ return(true);
+
+ return(false);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a hash code value for this object. Overrides the
+ * Permission.hashCode()
+ *
+ * @return A hash code
+ */
+public int
+hashCode()
+{
+ int hash = 100;
+
+ //*** Get a real hash function
+ for (int i = 0; i < hostport.length(); i++)
+ hash = hash + (int)hostport.charAt(i) * 7;
+
+ return(hash);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the list of permission actions in this object in canonical
+ * order. The canonical order is "connect,listen,accept,resolve"
+ *
+ * @return The permitted action string
+ */
+public String
+getActions()
+{
+ boolean found = false;
+ StringBuffer sb = new StringBuffer("");
+
+ if (perms.indexOf("connect") != -1)
+ {
+ sb.append("connect");
+ found = true;
+ }
+
+ if (perms.indexOf("listen") != -1)
+ if (found)
+ sb.append(",listen");
+ else
+ {
+ sb.append("listen");
+ found = true;
+ }
+
+ if (perms.indexOf("accept") != -1)
+ if (found)
+ sb.append(",accept");
+ else
+ {
+ sb.append("accept");
+ found = true;
+ }
+
+ if (found)
+ sb.append(",resolve");
+ else if (perms.indexOf("resolve") != -1)
+ sb.append("resolve");
+
+ return(sb.toString());
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a new PermissionCollection object that can hold
+ * SocketPermission's. Overrides Permission.newPermissionCollection
+ *
+ * @return A new PermissionCollection
+ */
+public PermissionCollection
+newPermissionCollection()
+{
+ //***Implement
+ return(null);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns true if the permission object passed it is implied by the
+ * this permission. This will be true if
+ * <p><ul>
+ * <li>The argument is of type SocketPermission
+ * <li>The permission list of the argument are in this object's permissions
+ * <li>The port range of the argument is within this objects port range
+ * <li>The hostname is equal to or a subset of this objects hostname
+ * </ul>
+ * <p>
+ * The argument's hostname will be a subset of this object's hostname if:
+ * <p><ul>
+ * <li>The argument's hostname or IP address is equal to this object's.
+ * <li>The argument's canonical hostname is equal to this object's.
+ * <li>The argument's canonical name matches this domains hostname with wildcards
+ * </ul>
+ *
+ * @param perm The Permission to check against
+ *
+ * @return True if the Permission is implied by this object, false otherwise
+ */
+public boolean
+implies(Permission perm)
+{
+ SocketPermission p;
+
+ // First make sure we are the right object type
+ if (perm instanceof SocketPermission)
+ p = (SocketPermission)perm;
+ else
+ return(false);
+
+ // Next check the actions
+ String ourlist = getActions();
+ String theirlist = p.getActions();
+
+ if (!ourlist.startsWith(theirlist))
+ return(false);
+
+ // Now check ports
+ int ourfirstport = 0, ourlastport = 0, theirfirstport = 0, theirlastport = 0;
+
+ // Get ours
+ if (hostport.indexOf(":") == -1)
+ {
+ ourfirstport = 0;
+ ourlastport = 65535;
+ }
+ else
+ {
+ // This will dump if hostport if all sorts of bad data was passed to
+ // the constructor
+ String range = hostport.substring(hostport.indexOf(":")+1);
+ if (range.startsWith("-"))
+ ourfirstport = 0;
+ else if (range.indexOf("-") == -1)
+ ourfirstport = Integer.parseInt(range);
+ else
+ ourfirstport = Integer.parseInt(range.substring(0,range.indexOf("-")));
+
+ if (range.endsWith("-"))
+ ourlastport=65535;
+ else if (range.indexOf("-") == -1)
+ ourlastport = Integer.parseInt(range);
+ else
+ ourlastport = Integer.parseInt(range.substring(range.indexOf("-")+1,
+ range.length()));
+ }
+
+ // Get theirs
+ if (p.hostport.indexOf(":") == -1)
+ {
+ theirfirstport = 0;
+ ourlastport = 65535;
+ }
+ else
+ {
+ // This will dump if hostport if all sorts of bad data was passed to
+ // the constructor
+ String range = p.hostport.substring(hostport.indexOf(":")+1);
+ if (range.startsWith("-"))
+ theirfirstport = 0;
+ else if (range.indexOf("-") == -1)
+ theirfirstport = Integer.parseInt(range);
+ else
+ theirfirstport = Integer.parseInt(range.substring(0,range.indexOf("-")));
+
+ if (range.endsWith("-"))
+ theirlastport=65535;
+ else if (range.indexOf("-") == -1)
+ theirlastport = Integer.parseInt(range);
+ else
+ theirlastport = Integer.parseInt(range.substring(range.indexOf("-")+1,
+ range.length()));
+ }
+
+ // Now check them
+ if ((theirfirstport < ourfirstport) || (theirlastport > ourlastport))
+ return(false);
+
+ // Finally we can check the hosts
+ String ourhost, theirhost;
+
+ // Get ours
+ if (hostport.indexOf(":") == -1)
+ ourhost = hostport;
+ else
+ ourhost = hostport.substring(0, hostport.indexOf(":"));
+
+ // Get theirs
+ if (p.hostport.indexOf(":") == -1)
+ theirhost = p.hostport;
+ else
+ theirhost = p.hostport.substring(0, p.hostport.indexOf(":"));
+
+ // Are they equal?
+ if (ourhost.equals(theirhost))
+ return(true);
+
+ // Try the canonical names
+ String ourcanonical = null, theircanonical = null;
+ try
+ {
+ ourcanonical = InetAddress.getByName(ourhost).getHostName();
+ theircanonical = InetAddress.getByName(theirhost).getHostName();
+ }
+ catch (UnknownHostException e)
+ {
+ // Who didn't resolve? Just assume current address is canonical enough
+ // Is this ok to do?
+ if (ourcanonical == null)
+ ourcanonical = ourhost;
+ if (theircanonical == null)
+ theircanonical = theirhost;
+ }
+
+ if (ourcanonical.equals(theircanonical))
+ return(true);
+
+ // Well, last chance. Try for a wildcard
+ if (ourhost.indexOf("*.") != -1)
+ {
+ String wild_domain = ourhost.substring(ourhost.indexOf("*" + 1));
+ if (theircanonical.endsWith(wild_domain))
+ return(true);
+ }
+
+ // Didn't make it
+ return(false);
+}
+
+} // class SocketPermission
+
diff --git a/java/net/TODO b/java/net/TODO
new file mode 100644
index 000000000..08215b6a6
--- /dev/null
+++ b/java/net/TODO
@@ -0,0 +1,26 @@
+-- DNS cache purging.
+
+-- Implement ContentHandler chaining (non-JDK feature)
+
+-- Implement MIME type by file determination chaining using external
+ disk files. (non-JDK feature)
+
+-- Implement determining MIME type from an InputStream
+
+-- Datagram peek()'s
+
+-- Finalize methods for sockets
+
+-- HTTP - caching (supported by JDK?)
+
+-- HTTP - all protocol support beyond basic GET functionality
+
+-- Fix call to Date(String) in URLConnection.getHeaderFieldDate() when
+ I figure out why DateFormat isn't working.
+
+-- Implement URLConnection.getPermission()
+
+-- Finish off all JDK 1.2 permissions stuff
+
+-- Write URLClassLoader
+
diff --git a/java/net/URL.java b/java/net/URL.java
new file mode 100644
index 000000000..79bae9824
--- /dev/null
+++ b/java/net/URL.java
@@ -0,0 +1,690 @@
+/*************************************************************************
+/* URL.java -- Uniform Resource Locator Class
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.StringTokenizer;
+import java.util.Hashtable;
+
+/**
+ * This final class represents an Internet Uniform Resource Locator (URL).
+ * For details on the syntax of URL's and what they can be used for,
+ * refer to RFC 1738, available from <a
+ * href="http://ds.internic.net/rfcs/rfc1738.txt">http://ds.internic.net/rfcs/rfc1738.txt</a>
+ * <p>
+ * There are a great many protocols supported by URL's such as "http",
+ * "ftp", and "file". This object can handle any arbitrary URL for which
+ * a URLStreamHandler object can be written. Default protocol handlers
+ * are provided for the "http" and "ftp" protocols. Additional protocols
+ * handler implementations may be provided in the future. In any case,
+ * an application or applet can install its own protocol handlers that
+ * can be "chained" with other protocol hanlders in the system to extend
+ * the base functionality provided with this class. (Note, however, that
+ * unsigned applets cannot access properties by default or install their
+ * own protocol handlers).
+ * <p>
+ * This chaining is done via the system property java.protocol.handler.pkgs
+ * If this property is set, it is assumed to be a "|" separated list of
+ * package names in which to attempt locating protocol handlers. The
+ * protocol handler is searched for by appending the string
+ * ".<protocol>.Handler" to each packed in the list until a hander is found.
+ * If a protocol handler is not found in this list of packages, or if the
+ * property does not exist, then the default protocol handler of
+ * "gnu.java.net.<protocol>.Handler" is tried. If this is
+ * unsuccessful, a MalformedURLException is thrown.
+ * <p>
+ * All of the constructor methods of URL attempt to load a protocol
+ * handler and so any needed protocol handlers must be installed when
+ * the URL is constructed.
+ * <p>
+ * Here is an example of how URL searches for protocol handlers. Assume
+ * the value of java.protocol.handler.pkgs is "com.foo|com.bar" and the
+ * URL is "news://comp.lang.java.programmer". URL would looking the
+ * following places for protocol handlers:
+ * <p><pre>
+ * com.foo.news.Handler
+ * com.bar.news.Handler
+ * gnu.java.net.news.Handler
+ * </pre><p>
+ * If the protocol handler is not found in any of those locations, a
+ * MalformedURLException would be thrown.
+ * <p>
+ * Please note that a protocol handler must be a subclass of
+ * URLStreamHandler.
+ * <p>
+ * Normally, this class caches protocol handlers. Once it finds a handler
+ * for a particular protocol, it never tries to look up a new handler
+ * again. However, if the system property
+ * gnu.java.net.nocache_protocol_handlers is set, then this
+ * caching behavior is disabled. This property is specific to this
+ * implementation. Sun's JDK may or may not do protocol caching, but it
+ * almost certainly does not examine this property.
+ * <p>
+ * Please also note that an application can install its own factory for
+ * loading protocol handlers (see setURLStreamHandlerFactory). If this is
+ * done, then the above information is superseded and the behavior of this
+ * class in loading protocol handlers is dependent on that factory.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * @see URLStreamHandler
+ */
+public final class URL implements Serializable //, Comparable
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
+ */
+
+/**
+ * If an application installs in own protocol handler factory, this is
+ * where we keep track of it.
+ */
+protected static URLStreamHandlerFactory factory;
+
+/**
+ * This a table where we cache protocol handlers to avoid the overhead
+ * of looking them up each time.
+ */
+protected static Hashtable ph_cache = new Hashtable();
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The name of the protocol for this URL
+ */
+protected String protocol;
+
+/**
+ * The hostname or IP address of this protocol
+ */
+protected String host;
+
+/**
+ * The port number of this protocol or -1 if the port number used is
+ * the default for this protocol.
+ */
+protected int port = -1;
+
+/**
+ * The "file" portion of the URL
+ */
+protected String file;
+
+/**
+ * The anchor portion of the URL
+ */
+protected String anchor;
+
+/**
+ * The protocol handler in use for this URL
+ */
+protected URLStreamHandler ph;
+
+/*************************************************************************/
+
+/*
+ * Static Methods
+ */
+
+/**
+ * Sets the URLStreamHandlerFactory for this class. This factory is
+ * responsible for returning the appropriate protocol handler for
+ * a given URL.
+ *
+ * @param fac The URLStreamHandlerFactory class to use
+ *
+ * @exception Error If the factory is alread set.
+ */
+public static synchronized void
+setURLStreamHandlerFactory(URLStreamHandlerFactory fac)
+{
+ if (factory == null)
+ factory = fac;
+ else
+ throw new Error("URLStreamHandlerFactory alread set");
+}
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Constructs a URL and loads a protocol handler for the values passed as
+ * arguments.
+ *
+ * @param protocol The protocol for this URL ("http", "ftp", etc)
+ * @param host The hostname or IP address to connect to
+ * @param port The port number to use, or -1 to use the protocol's default port
+ * @param file The "file" portion of the URL.
+ *
+ * @exception MalformedURLException If a protocol handler cannot be loaded
+ */
+public
+URL(String protocol, String host, int port, String file)
+ throws MalformedURLException
+{
+ this.protocol = protocol.toLowerCase();
+ this.host = host;
+ this.port = port;
+ this.file = file;
+
+ ph = getProtocolHandler(protocol);
+}
+
+/*************************************************************************/
+
+/**
+ * Constructs a URL and loads a protocol handler for the values passed in
+ * as arugments. Uses the default port for the protocol.
+ *
+ * @param protocol The protocol for this URL ("http", "ftp", etc)
+ * @param host The hostname or IP address for this URL
+ * @param file The "file" portion of this URL.
+ *
+ * @exception MalformedURLException If a protocol handler cannot be loaded
+ */
+public
+URL(String protocol, String host, String file) throws MalformedURLException
+{
+ this(protocol, host, -1, file);
+}
+
+/*************************************************************************/
+
+/**
+ * This method parses a String representation of a URL within the
+ * context of an existing URL. Principally this means that any fields
+ * not present the URL are inheritied from the context URL. This allows
+ * relative URL's to be easily constructed (***true?***). If the
+ * context argument is null, then a complete URL must be specified in the
+ * URL string. If the protocol parsed out of the URL is different
+ * from the context URL's protocol, then then URL String is also
+ * expected to be a complete URL.
+ *
+ * @param context The context URL
+ * @param url A String representing this URL
+ *
+ * @exception MalformedURLException If a protocol handler cannot be found or the URL cannot be parsed
+ */
+public
+URL(URL context, String url) throws MalformedURLException
+{
+ int end, start = -1;
+
+ int colon_index = url.indexOf(":");
+ int slash_index = url.indexOf("/");
+
+ // Find a protocol name in the string if there is one
+ if (colon_index != -1)
+ if ((slash_index == -1) ||((slash_index != -1) &&
+ (colon_index < slash_index)))
+ {
+ protocol = url.substring(0, colon_index);
+ start = colon_index + 1; // Used for parsing later
+ }
+
+ // Handle defaulting of protocol from context. If no protocol and no
+ // context, then no URL.
+ if (protocol == null)
+ if (context == null)
+ throw new MalformedURLException(url);
+ else
+ protocol = context.getProtocol();
+
+ protocol = protocol.toLowerCase();
+
+ // Default in items as necessary
+ if (context != null)
+ if (context.getProtocol().equals(protocol))
+ {
+ host = context.getHost();
+ port = context.getPort();
+ file = context.getFile();
+ }
+
+ // Get the protocol handler and parse the rest of the URL string.
+ ph = getProtocolHandler(protocol);
+
+ if (start == -1)
+ start = 0;
+
+ // We are supposed to stop parsing at the "#" char and treat everything
+ // after that as an anchor.
+ end = url.indexOf("#");
+ if (end == -1)
+ end = url.length();
+ if (end != (url.length()))
+ anchor = url.substring(end + 1);
+
+ ph.parseURL(this, url, start, end);
+}
+
+/*************************************************************************/
+
+/**
+ * Initializes a URL from a complete string specification such as
+ * "http://www.urbanophile.com/arenn/". First the protocol name is parsed
+ * out of the string. Then a handler is located for that protocol and
+ * the parseURL() method of that protocol handler is used to parse the
+ * remaining fields.
+ *
+ * @param url The complete String representation of a URL
+ *
+ * @exception MalformedURLException If a protocol handler cannot be found or the URL cannot be parsed
+ */
+public
+URL(String url) throws MalformedURLException
+{
+ this(null, url);
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * This internal method is used in two different constructors to load
+ * a protocol handler for this URL.
+ *
+ * @param The protocol to load a handler for
+ *
+ * @return A URLStreamHandler for this protocol
+ *
+ * @exception MalformedURLException If the protocol can't be loaded.
+ */
+private URLStreamHandler
+getProtocolHandler(String protocol) throws MalformedURLException
+{
+ URLStreamHandler ph;
+
+ // First check the factory and use that if set
+ if (factory != null)
+ {
+ ph = factory.createURLStreamHandler(protocol);
+ if (ph == null)
+ throw new MalformedURLException(protocol);
+ }
+
+ // Next check the cache unless the user has disabled caches
+ String nocache = null;
+ try
+ {
+ nocache = System.getProperty("gnu.java.net.nocache_protocol_handlers");
+ }
+ catch (SecurityException e) { ; }
+
+ if (nocache == null)
+ {
+ Class cls = (Class)ph_cache.get(protocol);
+ if (cls != null)
+ {
+ try
+ {
+ ph = (URLStreamHandler)cls.newInstance();
+ return(ph);
+ }
+ catch (InstantiationException e) { ; }
+ catch (IllegalAccessException e) { ; }
+ }
+ }
+
+ // Next, get the protocol handler package list property
+ String pkglist = null;
+ try
+ {
+ pkglist = System.getProperty("java.protocol.handler.pkgs");
+ }
+ catch (SecurityException e) { ; }
+
+ // Tack our default package on at the ends
+ if (pkglist != null)
+ pkglist = pkglist + "|" + "gnu.java.net";
+ else
+ pkglist = "gnu.java.net";
+
+ // Now loop through looking for a match
+ if (pkglist != null)
+ {
+ StringTokenizer st = new StringTokenizer(pkglist, "|");
+ while (st.hasMoreTokens())
+ {
+ String clsname = st.nextToken() + "." + protocol + ".Handler";
+
+ try
+ {
+ Class cls = Class.forName(clsname);
+ Object obj = cls.newInstance();
+ if (!(obj instanceof URLStreamHandler))
+ continue;
+ else
+ ph = (URLStreamHandler)obj;
+
+ if (nocache != null)
+ ph_cache.put(protocol, cls);
+
+ return(ph);
+ }
+ catch (ClassNotFoundException e) { ; }
+ catch (InstantiationException e) { ; }
+ catch (IllegalAccessException e) { ; }
+ }
+ }
+
+ // Still here, which is bad new
+ throw new MalformedURLException(protocol);
+}
+
+/*************************************************************************/
+
+/**
+ * This protected method is used by protocol handlers to set the values
+ * of the fields in this URL. This might be done in the parseURL method
+ * of that class.
+ *
+ * @param protocol The protocol name for this URL
+ * @param host The hostname or IP address for this URL
+ * @param port The port number of this URL
+ * @param file The "file" portion of this URL.
+ * @param anchor The anchor portion of this URL.
+ */
+protected synchronized void
+set(String protocol, String host, int port, String file, String anchor)
+{
+ //*** Should we ignore null'd fields? Assume not for now.
+
+ this.protocol = protocol;
+ this.host = host;
+ this.port = port;
+ this.file = file;
+ this.anchor = anchor;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the protocol name of this URL
+ *
+ * @return The protocol
+ */
+public String
+getProtocol()
+{
+ return(protocol);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the hostname or IP address for this protocol
+ *
+ * @return The hostname
+ */
+public String
+getHost()
+{
+ return(host);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the port number of this URL or -1 if the default port number is
+ * being used
+ *
+ * @return The port number
+ */
+public int
+getPort()
+{
+ return(port);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the "file" portion of this URL
+ *
+ * @return The file portion
+ */
+public String
+getFile()
+{
+ return(file);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the anchor (sometimes called the "reference") portion of the
+ * URL
+ *
+ * @return The anchor
+ */
+public String
+getRef()
+{
+ return(anchor);
+}
+
+/*************************************************************************/
+
+/**
+ * Test another URL for equality with this one. This will be true only if
+ * the argument is non-null and all of the fields in the URL's match
+ * exactly (ie, protocol, host, port, file, and anchor). Overrides
+ * Object.equals().
+ *
+ * @param url The URL to compare with
+ *
+ * @return true if the URL is equal, false otherwise
+ */
+public boolean
+equals(Object url)
+{
+ // Is it null?
+ if (url == null)
+ return(false);
+
+ // Is it a URL?
+ if (!(url instanceof URL))
+ return(false);
+
+ URL u = (URL)url;
+
+ // Check everything but the anchor
+ if (!sameFile(u))
+ return(false);
+
+ // Do the anchor's match
+ String s = u.getRef();
+ if (s != null)
+ if (!s.equals(getRef()))
+ return(false);
+ else if (getRef() != null)
+ return(false);
+
+ // Still here so everything must be ok
+ return(true);
+}
+
+/*************************************************************************/
+
+/**
+ * Tests whether or not another URL refers to the same "file" as this one.
+ * This will be true if and only if the passed object is not null, is a
+ * URL, and matches all fields but the anchor (ie, protocol, host, port,
+ * and file);
+ *
+ * @param url The URL object to test with
+ *
+ * @return true if URL matches this URL's file, false otherwise
+ */
+public boolean
+sameFile(URL url)
+{
+ if (url == null)
+ return(false);
+
+ // Do the protocol's match?
+ String s = url.getProtocol();
+ if (s != null)
+ if (!s.equals(getProtocol()))
+ return(false);
+ else if (getProtocol() != null)
+ return(false);
+
+ // Do the hostname's match?
+ s = url.getHost();
+ if (s != null)
+ if (!s.equals(getHost()))
+ return(false);
+ else if (getHost() != null)
+ return(false);
+
+ // Do the port's match?
+ if (url.getPort() != getPort())
+ return(false);
+
+ // Do the file's match?
+ s = url.getFile();
+ if (s != null)
+ if (!s.equals(getFile()))
+ return(false);
+ else if (getFile() != null)
+ return(false);
+
+ // We're still here, so everything must be ok!
+ return(true);
+}
+
+/*************************************************************************/
+
+/**
+ * This is the implementation of the Comparable interface for URL's. It
+ * will return a negative int, 0, or a positive int depending on whether
+ * a URL is less than, equal to, or greater than this URL respectively.
+ * This is done by returning the compareTo result on this string
+ * representations of these URL's.
+ *
+ * @param url The URL to compare against
+ *
+ * @return An int indicating whether a URL is less than, equal to, or greater than this URL
+ */
+public int
+compareTo(Object url)
+{
+ return(toExternalForm().compareTo(((URL)url).toExternalForm()));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a String representing this URL. The String returned is
+ * created by calling the protocol handler's toExternalForm() method.
+ *
+ * @return A string for this URL
+ */
+public String
+toExternalForm()
+{
+ return(ph.toExternalForm(this));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a String representing this URL. Identical to toExternalForm().
+ * The value returned is created by the protocol handler's
+ * toExternalForm method. Overrides Object.toString()
+ *
+ * @return A string for this URL
+ */
+public String
+toString()
+{
+ return(toExternalForm());
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a URLConnection for this object created by calling the
+ * openConnection() method of the protocol handler
+ *
+ * @return A URLConnection for this URL
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized URLConnection
+openConnection() throws IOException
+{
+ return(ph.openConnection(this));
+}
+
+/*************************************************************************/
+
+/**
+ * This method returns an InputStream for this URL by first opening the
+ * connection, then calling the getInputStream() method against the
+ * connection.
+ *
+ * @return An InputStream for this URL
+ *
+ * @exception IOException If an error occurs
+ */
+public final synchronized InputStream
+openStream() throws IOException
+{
+ return(openConnection().getInputStream());
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the contents of this URL as an object by first opening a
+ * connection, then calling the getContent() method against the connection
+ *
+ * @return A content object for this URL
+ *
+ * @exception IOException If an error occurs
+ */
+public final synchronized Object
+getContent() throws IOException
+{
+ return(openConnection().getContent());
+}
+
+} // class URL
+
diff --git a/java/net/URLConnection.java b/java/net/URLConnection.java
new file mode 100644
index 000000000..131f1830b
--- /dev/null
+++ b/java/net/URLConnection.java
@@ -0,0 +1,912 @@
+/*************************************************************************
+/* URLConnection.java -- Abstract superclass for reading from URL's
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+//import java.security.Permission;
+import java.text.DateFormat;
+import java.text.ParsePosition;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Vector;
+
+/**
+ * This class models a connection that retrieves the information pointed
+ * to by a URL object. This is typically a connection to a remote node
+ * on the network, but could be a simple disk read.
+ * <p>
+ * A URLConnection object is normally created by calling the openConnection()
+ * method of a URL object. This method is somewhat misnamed because it does
+ * not actually open the connection. Instead, it return an unconnected
+ * instance of this object. The caller then has the opportunity to set
+ * various connection options prior to calling the actual connect() method.
+ * <p>
+ * After the connection has been opened, there are a number of methods in
+ * this class that access various attributes of the data, typically
+ * represented by headers sent in advance of the actual data itself.
+ * <p>
+ * Also of note are the getInputStream and getContent() methods which allow
+ * the caller to retrieve the actual data from the connection. Note that
+ * for some types of connections, writing is also allowed. The setDoOutput()
+ * method must be called prior to connecing in order to enable this, then
+ * the getOutputStream method called after the connection in order to
+ * obtain a stream to write the output to.
+ * <p>
+ * The getContent() method is of particular note. This method returns an
+ * Object that encapsulates the data returned. There is no way do determine
+ * the type of object that will be returned in advance. This is determined
+ * by the actual content handlers as described in the description of that
+ * method.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract class URLConnection
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
+ */
+
+/**
+ * This is an object that maps filenames to MIME types. The interface
+ * to do this is implemented by this class, so just create an empty
+ * instance and store it here.
+ */
+public static FileNameMap fileNameMap = new MimeTypeMapper();
+
+/**
+ * This is the ContentHandlerFactory set by the caller, if any
+ */
+private static ContentHandlerFactory factory;
+
+/**
+ * This is the default value that will be used to determine whether or
+ * not user interaction should be allowed.
+ */
+private static boolean def_allow_user_inter;
+
+/**
+ * This is the default flag indicating whether or not to use caches to
+ * store the data returned from a server
+ */
+private static boolean def_use_caches;
+
+/**
+ * This is a Hashable for setting default request properties
+ */
+private static Hashtable def_req_props = new Hashtable();
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * This variable determines whether or not interaction is allowed with
+ * the user. For example, to prompt for a username and password.
+ */
+protected boolean allowUserInteraction;
+
+/**
+ * Indicates whether or not a connection has been established to the
+ * destination specified in the URL
+ */
+protected boolean connected;
+
+/**
+ * Indicates whether or not input can be read from this URL
+ */
+protected boolean doInput;
+
+/**
+ * Indicates whether or not output can be sent to this URL
+ */
+protected boolean doOutput;
+
+/**
+ * Determines whether or not caches should be used for this URL.
+ * Setting this to true does not guarantee that caching will take place,
+ * only that caching will take place if possible
+ */
+protected boolean useCaches;
+
+/**
+ * If this value is non-zero, then the connection will only attempt to
+ * fetch the document pointed to by the URL if the document has been
+ * modified more recently than the date set in this variable. That date
+ * should be specified as the number of seconds since 1/1/1970 GMT.
+ */
+protected long ifModifiedSince;
+
+/**
+ * This is the URL associated with this connection
+ */
+protected URL url;
+
+/**
+ * This is the list of header tag or key fields. Use a Vector instead of
+ * a Hastable because we need to reference by index. Use the "standard"
+ * Java naming in the hope that it is compatible with Sun's implementation
+ * Use Vector for JDK 1.1.5 compat.
+ */
+protected Vector headerKeys = new Vector(10);
+
+/**
+ * This is the list of header value fields. Use a Vector instead of
+ * a Hastable because we need to reference by index. Use the "standard"
+ * Java naming in the hope that it is compatible with Sun's implementation
+ * Use Vector for JDK 1.1.5 compat.
+ */
+protected Vector headerValues = new Vector(10);
+
+/**
+ * The list of request properties for this connection
+ */
+private Hashtable req_props = new Hashtable(10);
+
+/*************************************************************************/
+
+/*
+ * Class Methods
+ */
+
+/**
+ * Set's the ContentHandlerFactory for an application. This can be called
+ * once and only once. If it is called again, then an Error is thrown.
+ * Unlike for other set factory methods, this one does not do a security
+ * check prior to setting the factory.
+ *
+ * @param factory The ContentHandlerFactory for this application
+ *
+ * @error Error If the factory is already set
+ */
+public static synchronized void
+setContentHandlerFactory(ContentHandlerFactory fac)
+{
+ if (factory != null)
+ throw new Error("The ContentHandlerFactory is already set");
+
+ factory = fac;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the default flag for whether or not interaction with a user
+ * is allowed. This will be used for all connections unless overidden
+ *
+ * @return true if user interaction is allowed, false otherwise
+ */
+public static boolean
+getDefaultAllowUserInteraction()
+{
+ return(def_allow_user_inter);
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the default flag for whether or not interaction with a user
+ * is allowed. This will be used for all connections unless overridden
+ *
+ * @param allow true to allow user interaction, false otherwise
+ */
+public static synchronized void
+setDefaultAllowUserInteraction(boolean allow)
+{
+ def_allow_user_inter = allow;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the default value used to determine whether or not caching
+ * of documents will be done when possible.
+ *
+ * @return true if caches will be used, false otherwise
+ */
+public static boolean
+getDefaultUseCaches()
+{
+ return(def_use_caches);
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the default value used to determine whether or not caching
+ * of documents will be done when possible.
+ *
+ * @param use true to use caches if possible by default, false otherwise
+ */
+public static synchronized void
+setDefaultUseCaches(boolean use)
+{
+ def_use_caches = use;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the default value of a request property. This will be used
+ * for all connections unless the value of the property is manually
+ * overridden.
+ *
+ * @param key The request property to return the default value of
+ *
+ * @return The default request property
+ */
+public static String
+getDefaultRequestProperty(String key)
+{
+ return((String)def_req_props.get(key.toLowerCase()));
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the default value of a request property. This will be used
+ * for all connections unless the value of the property is manually
+ * overridden.
+ *
+ * @param key The request property name the default is being set for
+ * @param value The value to set the default to
+ */
+public static synchronized void
+setDefaultRequestProperty(String key, String value)
+{
+ def_req_props.put(key.toLowerCase(), value);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the MIME type of a file based on the name of the file. This
+ * works by searching for the file's extension in a list of file extensions
+ * and returning the MIME type associated with it. If no type is found,
+ * then a MIME type of "application/octet-stream" will be returned.
+ *
+ * @param filename The filename to determine the MIME type for
+ *
+ * @return The MIME type String
+ */
+protected static String
+guessContentTypeFromName(String filename)
+{
+ return(fileNameMap.getContentTypeFor(filename.toLowerCase()));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the MIME type of a stream based on the first few characters
+ * at the beginning of the stream. This routine can be used to determine
+ * the MIME type if a server is believed to be returning an incorrect
+ * MIME type. This method returns "application/octet-stream" if it
+ * cannot determine the MIME type.
+ * <p>
+ * NOTE: Overriding MIME types sent from the server can be obnoxious
+ * to user's. See Internet Exploder 4 if you don't believe me.
+ *
+ * @param is The InputStream to determine the MIME type from
+ *
+ * @return The MIME type
+ *
+ * @exception IOException If an error occurs
+ */
+public static String
+guessContentTypeFromStream(InputStream is) throws IOException
+{
+ return("application/octet-stream");
+}
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * This constructs a URLConnection from a URL object
+ *
+ * @param url The URL for this connection
+ */
+protected
+URLConnection(URL url)
+{
+ // Set up all our instance variables
+ this.url = url;
+ allowUserInteraction = def_allow_user_inter;
+ useCaches = def_use_caches;
+
+ Enumeration e = def_req_props.keys();
+ while (e.hasMoreElements())
+ {
+ String key = (String)e.nextElement();
+ String value = (String)def_req_props.get(key);
+
+ req_props.put(key, value);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a boolean flag indicating whether or not user interaction is
+ * allowed for this connection. (For example, in order to prompt for
+ * username and password info.
+ *
+ * @return true if user interaction is allowed, false otherwise
+ */
+public boolean
+getAllowUserInteraction()
+{
+ return(allowUserInteraction);
+}
+
+/*************************************************************************/
+
+/**
+ * Sets a boolean flag indicating whether or not user interaction is
+ * allowed for this connection. (For example, in order to prompt for
+ * username and password info.
+ *
+ * @param allow true if user interaction should be allowed, false otherwise
+ */
+public void
+setAllowUserInteraction(boolean allow)
+{
+ allowUserInteraction = allow;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of a flag indicating whether or not input is going
+ * to be done for this connection. This default to true unless the
+ * doOutput flag is set to false, in which case this defaults to false.
+ *
+ * @return true if input is to be done, false otherwise
+ */
+public boolean
+getDoInput()
+{
+ return(doInput);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of a flag indicating whether or not input is going
+ * to be done for this connection. This default to true unless the
+ * doOutput flag is set to false, in which case this defaults to false.
+ *
+ * @param input true if input is to be done, false otherwise
+ */
+public void
+setDoInput(boolean input)
+{
+ doInput = input;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a boolean flag indicating whether or not output will be done
+ * on this connection. This defaults to false.
+ *
+ * @return true if output is to be done, false otherwise
+ */
+public boolean
+getDoOutput()
+{
+ return(doOutput);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a boolean flag indicating whether or not output will be done
+ * on this connection. The default value is false, so this method can
+ * be used to override the default
+ *
+ * @param output ture if output is to be done, false otherwise
+ */
+public void
+setDoOutput(boolean output)
+{
+ doOutput = output;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a boolean flag indicating whether or not caching will be used
+ * (if possible) to store data downloaded via the connection.
+ *
+ * @return true if caching should be used if possible, false otherwise
+ */
+public boolean
+getUseCaches()
+{
+ return(useCaches);
+}
+
+/*************************************************************************/
+
+/**
+ * Sets a boolean flag indicating whether or not caching will be used
+ * (if possible) to store data downloaded via the connection.
+ *
+ * @param use_cache true if caching should be used if possible, false otherwise
+ */
+public void
+setUseCaches(boolean use_caches)
+{
+ useCaches = use_caches;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the ifModified since instance variable. If this value is non
+ * zero and the underlying protocol supports it, the actual document will
+ * not be fetched unless it has been modified since this time. The value
+ * returned will be 0 if this feature is disabled or the time expressed
+ * as the number of seconds since midnight 1/1/1970 GMT otherwise
+ *
+ * @return The ifModifiedSince value
+ */
+public long
+getIfModifiedSince()
+{
+ return(ifModifiedSince);
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the ifModified since instance variable. If this value is non
+ * zero and the underlying protocol supports it, the actual document will
+ * not be fetched unless it has been modified since this time. The value
+ * passed should be 0 if this feature is to be disabled or the time expressed
+ * as the number of seconds since midnight 1/1/1970 GMT otherwise.
+ *
+ * @param modified_since The new ifModifiedSince value
+ */
+public void
+setIfModifiedSince(long modified_since)
+{
+ ifModifiedSince = modified_since;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the named request property.
+ *
+ * @param key The name of the property
+ *
+ * @return The value of the property
+ */
+public String
+getRequestProperty(String key)
+{
+ return((String)req_props.get(key.toLowerCase()));
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the value of the named request property
+ *
+ * @param key The name of the property
+ * @param value The value of the property
+ */
+public synchronized void
+setRequestProperty(String key, String value)
+{
+ req_props.put(key.toLowerCase(), value);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the URL object associated with this connection
+ *
+ * @return The URL for this connection.
+ */
+public URL
+getURL()
+{
+ return(url);
+}
+
+/*************************************************************************/
+
+/**
+ * Establishes the actual connection to the URL associated with this
+ * connection object
+ */
+public abstract void
+connect() throws IOException;
+
+/*************************************************************************/
+
+/**
+ * Returns an InputStream for this connection. As this default
+ * implementation returns null, subclasses should override this method
+ *
+ * @return An InputStream for this connection
+ *
+ * @exception IOException If an error occurs
+ */
+public InputStream
+getInputStream() throws IOException
+{
+ return(null);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns an OutputStream for this connection. As this default
+ * implementation returns null, subclasses should override this method
+ *
+ * @return An OutputStream for this connection
+ *
+ * @exception IOException If an error occurs
+ */
+public OutputStream
+getOutputStream() throws IOException
+{
+ return(null);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the content-encoding field or null if it is not
+ * known or not present.
+ *
+ * @return The content-encoding field
+ */
+public String
+getContentEncoding()
+{
+ return(getHeaderField("content-encoding"));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the content-length header field or -1 if the value
+ * is not known or not present.
+ *
+ * @return The content-length field
+ */
+public int
+getContentLength()
+{
+ return(getHeaderFieldInt("content-length", -1));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the the content-type of the data pointed to by the URL. This
+ * method first tries looking for a content-type header. If that is not
+ * present, it attempts to use the file name to determine the content's
+ * MIME type. If that is unsuccessful, the method returns null. The caller
+ * may then still attempt to determine the MIME type by a call to
+ * guessContentTypeFromStream()
+ *
+ * @return The content MIME type
+ */
+public String
+getContentType()
+{
+ String type = getHeaderField("content-type");
+ if (type == null)
+ type = guessContentTypeFromName(getURL().getFile());
+
+ return(type);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the date of the document pointed to by the URL as reported in
+ * the date field of the header or 0 if the value is not present or not
+ * known. If populated, the return value is number of seconds since
+ * midnight on 1/1/1970 GMT.
+ *
+ * @return The document date
+ */
+public long
+getDate()
+{
+ return(getHeaderFieldDate("date", 0));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the expires header or 0 if not known or present.
+ * If populated, the return value is number of seconds since midnight
+ * on 1/1/1970 GMT.
+ *
+ * @return The expiration time.
+ */
+public long
+getExpiration()
+{
+ return(getHeaderFieldDate("expires", 0));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the last-modified header field or 0 if not known known
+ * or not present. If populated, the return value is the number of seconds
+ * since midnight on 1/1/1970.
+ *
+ * @return The last modified time
+ */
+public long
+getLastModified()
+{
+ return(getHeaderFieldDate("last-modified", 0));
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a String representing the header key at the specified index.
+ * This allows the caller to walk the list of header fields. The analogous
+ * getHeaderField(int) method allows access to the corresponding value for
+ * this tag.
+ *
+ * @param index The index into the header field list to retrieve the key for.
+ *
+ * @return The header field key or null if index is past the end of the headers
+ */
+public String
+getHeaderFieldKey(int index)
+{
+ String key = null;
+
+ try
+ {
+ key = (String)headerKeys.elementAt(index);
+ }
+ catch (ArrayIndexOutOfBoundsException e) { ; }
+
+ return(key);
+}
+
+/*************************************************************************/
+
+/**
+ * Return a String representing the header value at the specified index.
+ * This allows the caller to walk the list of header fields. The analogous
+ * getHeaderFieldKey(int) method allows access to the corresponding key
+ * for this header field
+ *
+ * @param index The index into the header field list to retrieve the value for
+ *
+ * @return The header value or null if index is past the end of the headers
+ */
+public String
+getHeaderField(int index)
+{
+ String value = null;
+
+ try
+ {
+ value = (String)headerValues.elementAt(index);
+ }
+ catch (ArrayIndexOutOfBoundsException e) { ; }
+
+ return(value);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a String representing the value of the header field having
+ * the named key. Returns null if the header field does not exist.
+ *
+ * @param The key of the header field
+ *
+ * @return The value of the header field as a String
+ */
+public String
+getHeaderField(String name)
+{
+ for (int i = 0; ; i++)
+ {
+ String key = getHeaderFieldKey(i);
+ if (key == null)
+ return(null);
+
+ if (key.equals(name.toLowerCase()))
+ return(getHeaderField(i));
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the named header field as a date. This date will
+ * be the number of seconds since midnight 1/1/1970 GMT or the default
+ * value if the field is not present or cannot be converted to a date.
+ *
+ * @param key The header field key to lookup
+ * @param def The default value if the header field is not found or can't be converted
+ */
+public long
+getHeaderFieldDate(String key, long def)
+{
+ String value = getHeaderField(key);
+ if (value == null)
+ return(def);
+
+ // This needs to change since Date(String) is deprecated, but DateFormat
+ // doesn't seem to be working for some reason
+ //DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, Locale.US);
+ //df.setLenient(true);
+
+ //Date d = df.parse(value, new ParsePosition(0));
+ Date d = new Date(value);
+
+ if (d == null)
+ return(def);
+
+ return(d.getTime() / 1000);
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the value of the named header field as an int. If the field
+ * is not present or cannot be parsed as an integer, the default value
+ * will be returned.
+ *
+ * @param key The header field key to lookup
+ * @param def The defaule value if the header field is not found or can't be parsed
+ */
+public int
+getHeaderFieldInt(String key, int def)
+{
+ String value = getHeaderField(key);
+ if (value == null)
+ return(def);
+
+ int retval = def;
+ try
+ {
+ retval = Integer.parseInt(value);
+ }
+ catch (NumberFormatException e)
+ {
+ return(def);
+ }
+
+ return(retval);
+}
+
+/*************************************************************************/
+
+/**
+ * What is this method supposed to do? It's not documented, so just
+ * throw an exception if called.
+ *
+ * @return A Permission object
+ *
+ * @exception IOException If an error occurs
+ */
+/*
+public Permission
+getPermission() throws IOException
+{
+ throw new IOException("I don't know what this method is supposed to do");
+}
+*/
+
+/*************************************************************************/
+
+/**
+ * This method returns the content of the document pointed to by the URL
+ * as an Object. The type of object depends on the MIME type of the
+ * object and particular content hander loaded. Most text type content
+ * handlers will return a subclass of InputStream. Images usually return
+ * a class that implements ImageProducer. There is not guarantee what
+ * type of object will be returned, however.
+ * <p>
+ * This class first determines the MIME type of the content, then creates
+ * a ContentHandler object to process the input. If the ContentHandlerFactory
+ * is set, then that object is called to load a content handler, otherwise
+ * a class called gnu.java.net.content.<content_type> is tried.
+ * The default class will also be used if the content handler factory returns
+ * a null content handler.
+ *
+ * @exception IOException If an error occurs.
+ */
+public Object
+getContent() throws IOException
+{
+// connect();
+ String type = getContentType();
+
+ // First try the factory
+ ContentHandler ch = null;
+ if (factory != null)
+ ch = factory.createContentHandler(type);
+
+ if (ch != null)
+ return(ch.getContent(this));
+
+ // Then try our default class
+ try
+ {
+ Class cls = Class.forName("gnu.java.net.content." +
+ type.replace('/', '.'));
+
+ Object obj = cls.newInstance();
+ if (!(obj instanceof ContentHandler))
+ throw new UnknownServiceException(type);
+
+ ch = (ContentHandler)obj;
+ return(ch.getContent(this));
+ }
+ catch (ClassNotFoundException e) { ; }
+ catch (InstantiationException e) { ; }
+ catch (IllegalAccessException e) { ; }
+
+ throw new UnknownServiceException(type);
+}
+
+/*************************************************************************/
+
+/**
+ * The methods prints the value of this object as a String by calling the
+ * toString() method of its associated URL. Overrides Object.toString()
+ *
+ * @return A String representation of this object
+ */
+public String
+toString()
+{
+ return(url.toString());
+}
+
+} // class URLConnection
+
diff --git a/java/net/URLEncoder.java b/java/net/URLEncoder.java
new file mode 100644
index 000000000..31ca6a138
--- /dev/null
+++ b/java/net/URLEncoder.java
@@ -0,0 +1,110 @@
+/*************************************************************************
+/* URLEncoder.java -- Class to convert strings to a properly encoded URL
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This utility class contains one static method that converts a
+ * string into a fully encoded URL string in x-www-form-urlencoded
+ * format. This format replaces certain disallowed characters with
+ * encoded equivalents. All upper case and lower case letters in the
+ * US alphabet remain as is, the space character (' ') is replaced with
+ * '+' sign, and all other characters are converted to a "%XX" format
+ * where XX is the hexadecimal representation of that character. Note
+ * that since unicode characters are 16 bits, and this metho encodes only
+ * 8 bits of information, the lower 8 bits of the character are used.
+ * <p>
+ * This method is very useful for encoding strings to be sent to CGI scripts
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class URLEncoder
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
+ */
+
+/**
+ * A lookup table array of hexadecimal character equivalents
+ */
+protected static final char[] hexchars = { '0', '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', 'A', 'B', 'C', 'D',
+ 'E', 'F' };
+
+/*************************************************************************/
+
+/*
+ * Class Methods
+ */
+
+/**
+ * This method translates the passed in string into x-www-form-urlencoded
+ * format and returns it.
+ *
+ * @param source The String to convert
+ *
+ * @return The converted String
+ */
+public static String
+encode(String source)
+{
+ StringBuffer result = new StringBuffer("");
+
+ for (int i = 0; i < source.length(); i++)
+ {
+ // Get the low 8 bits of the next char
+ char c = source.charAt(i);
+ c &= 0xFF;
+
+ // Handle regular characters
+ if ((c >= 'A') && (c <= 'Z'))
+ {
+ result.append(c);
+ continue;
+ }
+
+ if ((c >= 'a') && (c <= 'z'))
+ {
+ result.append(c);
+ continue;
+ }
+
+ // Handle spaces
+ if (c == ' ')
+ {
+ result.append('+');
+ continue;
+ }
+
+ // Handle everything else
+ result.append('%');
+ result.append(hexchars[ c / 16 ]);
+ result.append(hexchars[ c % 16 ]);
+ }
+
+ return(result.toString());
+}
+
+} // class URLEncoder
+
diff --git a/java/net/URLStreamHandler.java b/java/net/URLStreamHandler.java
new file mode 100644
index 000000000..af55513cb
--- /dev/null
+++ b/java/net/URLStreamHandler.java
@@ -0,0 +1,251 @@
+/*************************************************************************
+/* URLStreamHandler.java -- Abstract superclass for all protocol handlers
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * This class is the superclass of all URL protocol handlers. The URL
+ * class loads the appropriate protocol handler to establish a connection
+ * to a (possibly) remote service (eg, "http", "ftp") and to do protocol
+ * specific parsing of URL's. Refer to the URL class documentation for
+ * details on how that class locates and loads protocol handlers.
+ * <p>
+ * A protocol handler implementation should override the openConnection()
+ * method, and optionally override the parseURL() and toExternalForm()
+ * methods if necessary. (The default implementations will parse/write all
+ * URL's in the same form as http URL's). A protocol specific subclass
+ * of URLConnection will most likely need to be created as well.
+ * <p>
+ * Note that the instance methods in this class are called as if they
+ * were static methods. That is, a URL object to act on is passed with
+ * every call rather than the caller assuming the URL is stored in an
+ * instance variable of the "this" object.
+ * <p>
+ * The methods in this class are protected and accessible only to subclasses.
+ * URLStreamConnection objects are intended for use by the URL class only,
+ * not by other classes (unless those classes are implementing protocols).
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * @see URL
+ */
+public abstract class URLStreamHandler
+{
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * Do nothing constructor for subclass
+ */
+public
+URLStreamHandler()
+{
+ ;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * Returns a URLConnection for the passed in URL. Note that this should
+ * not actually create the connection to the (possibly) remote host, but
+ * rather simply return a URLConnection object. The connect() method of
+ * URL connection is used to establish the actual connection, possibly
+ * after the caller sets up various connection options.
+ *
+ * @param url The URL to get a connection object for
+ *
+ * @return A URLConnection object for the given URL
+ *
+ * @exception IOException If an error occurs
+ */
+protected abstract synchronized URLConnection
+openConnection(URL url) throws IOException;
+
+/*************************************************************************/
+
+/**
+ * This method parses the string passed in as a URL and set's the
+ * instance data fields in the URL object passed in to the various values
+ * parsed out of the string. The start parameter is the position to start
+ * scanning the string. This is usually the position after the ":" which
+ * terminates the protocol name. The end parameter is the position to
+ * stop scanning. This will be either the end of the String, or the
+ * position of the "#" character, which separates the "file" portion of
+ * the URL from the "anchor" portion.
+ * <p>
+ * This method assumes URL's are formatted like http protocol URL's, so
+ * subclasses that implement protocols with URL's the follow a different
+ * syntax should override this method. The lone exception is that if
+ * the protocol name set in the URL is "file", this method will accept
+ * a an empty hostname (i.e., "file:///"), which is legal for that protocol
+ *
+ * @param url The URL object in which to store the results
+ * @param url_string The String-ized URL to parse
+ * @param start The position in the string to start scanning from
+ * @param end The position in the string to stop scanning
+ */
+protected void
+parseURL(URL url, String url_string, int start, int end)
+{
+ // This method does not throw an exception or return a value. Thus our
+ // strategy when we encounter an error in parsing is to return without
+ // doing anything.
+
+ // Bunches of things should be true. Make sure.
+ if (end < start)
+ return;
+ if ((end - start) < 2)
+ return;
+ if (start > url_string.length())
+ return;
+ if (end > url_string.length())
+ end = url_string.length(); // This should be safe
+
+ // Turn end into an offset from the end of the string instead of
+ // the beginning
+ end = url_string.length() - end;
+
+ // Skip remains of protocol
+ url_string = url_string.substring(start);
+ if (!url_string.startsWith("//"))
+ return;
+ url_string = url_string.substring(2);
+
+ // Declare some variables
+ String host = null;
+ int port = -1;
+ String file = null;
+ String anchor = null;
+
+ // Process host and port
+ int slash_index = url_string.indexOf("/");
+ int colon_index = url_string.indexOf(":");
+
+ if (slash_index > (url_string.length() - end))
+ return;
+ else if (slash_index == -1)
+ slash_index = url_string.length() - end;
+
+ if ((colon_index == -1) || (colon_index > slash_index))
+ {
+ host = url_string.substring(0, slash_index);
+ }
+ else
+ {
+ host = url_string.substring(0, colon_index);
+
+ String port_str = url_string.substring(colon_index + 1, slash_index);
+ try
+ {
+ port = Integer.parseInt(port_str);
+ }
+ catch (NumberFormatException e)
+ {
+ return;
+ }
+ }
+ if (slash_index < (url_string.length() - 1))
+ url_string = url_string.substring(slash_index + 1);
+ else
+ url_string = "";
+
+ // Process file and anchor
+ if (end == 0)
+ {
+ file = "/" + url_string;
+ anchor = null;
+ }
+ else
+ {
+ file = "/" + url_string.substring(0, url_string.length() - end);
+
+ // Only set anchor if end char is a '#'. Otherwise assume we're
+ // just supposed to stop scanning for some reason
+ if (url_string.charAt(url_string.length() - end) == '#')
+ anchor = url_string.substring((url_string.length() - end) + 1,
+ url_string.length());
+ else
+ anchor = null;
+ }
+ if ((file == null) || (file == ""))
+ file = "/";
+
+ // Now set the values
+ setURL(url, url.getProtocol(), host, port, file, anchor);
+}
+
+/*************************************************************************/
+
+/**
+ * This method converts a URL object into a String. This method creates
+ * Strings in the mold of http URL's, so protocol handlers which use URL's
+ * that have a different syntax should override this method
+ *
+ * @param url The URL object to convert
+ */
+protected String
+toExternalForm(URL url)
+{
+ String protocol = url.getProtocol();
+ String host = url.getHost();
+ int port = url.getPort();
+ String file = url.getFile();
+ String anchor = url.getRef();
+
+ return(((protocol != null) ? (protocol + "://") : "") +
+ ((host != null) ? host : "") +
+ ((port != -1) ? (":" + port) : "") +
+ ((file != null) ? file : "/") +
+ ((anchor != null) ? ("#" + anchor) : ""));
+}
+
+/*************************************************************************/
+
+/**
+ * This methods sets the instance variables representing the various fields
+ * of the URL to the values passed in.
+ *
+ * @param url The URL in which to set the values
+ * @param protocol The protocol name
+ * @param host The host name
+ * @param port The port number
+ * @param file The file portion
+ * @param anchor The anchor portion
+ */
+protected void
+setURL(URL url, String protocol, String host, int port, String file,
+ String anchor)
+{
+ url.set(protocol, host, port, file, anchor);
+}
+
+} // class URLStreamHandler
+
diff --git a/java/net/URLStreamHandlerFactory.java b/java/net/URLStreamHandlerFactory.java
new file mode 100644
index 000000000..bbc9f64c0
--- /dev/null
+++ b/java/net/URLStreamHandlerFactory.java
@@ -0,0 +1,44 @@
+/*************************************************************************
+/* URLStreamHandlerFactory.java -- Maps protocols to URLStreamHandlers
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This interface contains one method which maps the protocol portion of
+ * a URL (eg, "http" in "http://www.urbanophile.com/arenn/") to a
+ * URLStreamHandler object.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public interface URLStreamHandlerFactory
+{
+/**
+ * This method maps the protocol portion of a URL to a URLStreamHandler
+ * object.
+ *
+ * @param protocol The protocol name to map ("http", "ftp", etc).
+ *
+ * @return The URLStreamHandler for the specified protocol
+ */
+public abstract URLStreamHandler
+createURLStreamHandler(String protocol);
+
+} // interface URLStreamHandlerFactory
diff --git a/java/net/UnknownHostException.java b/java/net/UnknownHostException.java
new file mode 100644
index 000000000..f8029771c
--- /dev/null
+++ b/java/net/UnknownHostException.java
@@ -0,0 +1,63 @@
+/*************************************************************************
+/* UnknownHostException.java -- The hostname is not unknown
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * This exception indicates that an attempt was made to reference a hostname
+ * or IP address that is not valid. This could possibly indicate that a
+ * DNS problem has occurred, but most often means that the host was not
+ * correctly specified.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class UnknownHostException extends java.io.IOException
+{
+
+/*
+ * Constructors
+ */
+
+/**
+ * Constructs a new UnknownHostException with no descriptive message.
+ */
+public
+UnknownHostException()
+{
+ super();
+}
+
+/*************************************************************************/
+
+/**
+ * Constructs a new UnknownHostException with a descriptive message (such as the
+ * text from strerror(3)) passed in as an argument
+ *
+ * @param message A message describing the error that occurs
+ */
+public
+UnknownHostException(String message)
+{
+ super(message);
+}
+
+} // class UnknownHostException
+
diff --git a/java/net/UnknownServiceException.java b/java/net/UnknownServiceException.java
new file mode 100644
index 000000000..5d74406cd
--- /dev/null
+++ b/java/net/UnknownServiceException.java
@@ -0,0 +1,63 @@
+/*************************************************************************
+/* UnknownServiceException.java -- A service error occured
+/*
+/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+/*
+/* This program is free software; you can redistribute it and/or modify
+/* it under the terms of the GNU Library General Public License as published
+/* by the Free Software Foundation, version 2. (see COPYING.LIB)
+/*
+/* This program 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 this program; if not, write to the Free Software Foundation
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+/*************************************************************************/
+
+package java.net;
+
+/**
+ * Contrary to what you might think, this does not indicate that the
+ * TCP/IP service name specified was invalid. Instead it indicates that
+ * the MIME type returned from a URL could not be determined or that an
+ * attempt was made to write to a read-only URL.
+ *
+ * @version 0.5
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class UnknownServiceException extends java.io.IOException
+{
+
+/*
+ * Constructors
+ */
+
+/**
+ * Constructs a new UnknownServiceException with no descriptive message.
+ */
+public
+UnknownServiceException()
+{
+ super();
+}
+
+/*************************************************************************/
+
+/**
+ * Constructs a new UnknownServiceException with a descriptive message (such as the
+ * text from strerror(3)) passed in as an argument
+ *
+ * @param message A message describing the error that occurs
+ */
+public
+UnknownServiceException(String message)
+{
+ super(message);
+}
+
+} // class UnknownServiceException
+
diff --git a/native/Makefile.am b/native/Makefile.am
new file mode 100644
index 000000000..778b94985
--- /dev/null
+++ b/native/Makefile.am
@@ -0,0 +1,8 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+SUBDIRS = java.net
+
+noinst_HEADERS = config.h config.h.in
+
+EXTRA_DIST = config.h.in
+
diff --git a/native/config.h b/native/config.h
new file mode 100644
index 000000000..a0e8de831
--- /dev/null
+++ b/native/config.h
@@ -0,0 +1 @@
+/* native/config.h. Generated automatically by configure. */
diff --git a/native/config.h.in b/native/config.h.in
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/native/config.h.in
diff --git a/native/java.net/ChangeLog b/native/java.net/ChangeLog
new file mode 100644
index 000000000..60525e511
--- /dev/null
+++ b/native/java.net/ChangeLog
@@ -0,0 +1,43 @@
+Wed Apr 22 21:39:11 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * javanet.c: Finished off native method support for multicast sockets
+
+Tue Apr 21 00:01:55 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * javanet.c: Lots of bug fixes to make datagram sockets work.
+
+ * PlainDatagramSocketImpl.c: Finished off receive(). Misc bug fixes
+ to get datagram sockets to work.
+
+Sun Apr 19 17:19:40 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * PlainDatagramSocketImpl.c: Wrote initial versions of all native
+ methods except receive
+
+Sat Apr 18 22:15:59 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * javanet.c: Completed all functionality needed for stream sockets
+ and tested basic functionality.
+
+Thu Apr 16 19:44:39 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * InetAddress.c: Cleaned up INADDR_ANY handling
+
+Wed Apr 15 23:24:06 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * PlainSocketImpl.c: Finished module. Mostly wrote methods here and
+ then copied them to javanet.c and redirected all calls from here
+ to those functions. Got a clean compile.
+
+ * javanet.h: New header file with decls for javanet.c
+
+ * javanet.c: Pulled the socket functions from PlainSocketImpl to here
+ to facilitate sharing with Datagram sockets. Implemented the
+ get/set functions for option handling. Modified the _javanet_throw*
+ function to take an addtional arg specifying the exception.
+
+Sun Apr 12 14:19:26 1998 arenn's Development Account <devel@larissa.foo.com>
+
+ * InetAddress.c: Created native library routines for InetAddress
+ class. Clean compile, install and test.
+
diff --git a/native/java.net/InetAddress.c b/native/java.net/InetAddress.c
new file mode 100644
index 000000000..c5c2dc105
--- /dev/null
+++ b/native/java.net/InetAddress.c
@@ -0,0 +1,190 @@
+/*************************************************************************
+ * InetAddress.c - Native methods for InetAddress class
+ *
+ * Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation, version 2. (see COPYING.LIB)
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+ *************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include <jni.h>
+
+#include "java_net_InetAddress.h"
+#include "java_net_InetAddress_stubs.c"
+
+#include "javanet.h"
+
+/*************************************************************************/
+
+/*
+ * Function to return the local hostname
+ */
+JNIEXPORT jstring JNICALL
+Java_java_net_InetAddress_getLocalHostName(JNIEnv *env, jclass class)
+{
+ char buf[255];
+ jstring retval;
+
+ if (gethostname(buf, sizeof(buf) - 1) == -1)
+ strcpy(buf, "localhost");
+
+ retval = (*env)->NewStringUTF(env, buf);
+
+ return(retval);
+}
+
+/*************************************************************************/
+
+/*
+ * Returns the value of the special IP address INADDR_ANY
+ */
+JNIEXPORT jarray JNICALL
+Java_java_net_InetAddress_lookupInaddrAny(JNIEnv *env, jclass class)
+{
+ jarray arr;
+ int *octets;
+
+ /* Allocate an array for the IP address */
+ arr = (*env)->NewIntArray(env, 4);
+ if (!arr)
+ return(_javanet_throw_exception(env, UNKNOWN_HOST_EXCEPTION,
+ "Internal Error"));
+
+ /* Copy in the values */
+ octets = (*env)->GetIntArrayElements(env, arr, 0);
+
+ octets[0] = (INADDR_ANY & 0xFF000000) >> 24;
+ octets[1] = (INADDR_ANY & 0x00FF0000) >> 16;
+ octets[2] = (INADDR_ANY & 0x0000FF00) >> 8;
+ octets[3] = (INADDR_ANY & 0x000000FF);
+
+ (*env)->ReleaseIntArrayElements(env, arr, octets, 0);
+
+ return(arr);
+}
+
+/*************************************************************************/
+
+/*
+ * Function to return the canonical hostname for a given IP address passed
+ * in as a byte array
+ */
+JNIEXPORT jstring JNICALL
+Java_java_net_InetAddress_getHostByAddr(JNIEnv *env, jclass class, jarray arr)
+{
+ jint *octets;
+ jsize len;
+ int addr;
+ struct hostent *hp;
+ jstring retval;
+
+ /* Grab the byte[] array with the IP out of the input data */
+ len = (*env)->GetArrayLength(env, arr);
+ if (len != 4)
+ return((int)_javanet_throw_exception(env, UNKNOWN_HOST_EXCEPTION,
+ "Bad IP Address"));
+
+ octets = (*env)->GetIntArrayElements(env, arr, 0);
+ if (!octets)
+ return(_javanet_throw_exception(env, UNKNOWN_HOST_EXCEPTION,
+ "Bad IP Address"));
+
+ /* Convert it to a 32 bit address */
+ addr = (octets[0] << 24) + (octets[1] << 16) + (octets[2] << 8) + octets[3];
+ addr = htonl(addr);
+
+ /* Release some memory */
+ (*env)->ReleaseIntArrayElements(env, arr, octets, 0);
+
+ /* Resolve the address and return the name */
+ hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET);
+ if (!hp)
+ return(_javanet_throw_exception(env, UNKNOWN_HOST_EXCEPTION,
+ "Bad IP Address"));
+
+ retval = (*env)->NewStringUTF(env, hp->h_name);
+
+ return(retval);
+}
+
+/*************************************************************************/
+
+JNIEXPORT jobjectArray JNICALL
+Java_java_net_InetAddress_getHostByName(JNIEnv *env, jclass class, jstring host)
+{
+ const char *hostname;
+ struct hostent *hp;
+ int i, ip, *octets;
+ jsize num_addrs;
+ jclass arr_class;
+ jobjectArray addrs;
+ jarray ret_octets;
+
+ /* Grab the hostname string */
+ hostname = (*env)->GetStringUTFChars(env, host, 0);
+ if (!hostname)
+ return(_javanet_throw_exception(env, UNKNOWN_HOST_EXCEPTION,
+ "Null hostname"));
+
+ /* Look up the host */
+ hp = gethostbyname(hostname);
+ if (!hp)
+ return(_javanet_throw_exception(env, UNKNOWN_HOST_EXCEPTION,
+ hostname));
+ (*env)->ReleaseStringUTFChars(env, host, hostname);
+
+ /* Figure out how many addresses there are and allocate a return array */
+ for (num_addrs = 0, i = 0; hp->h_addr_list[i] ; i++)
+ ++num_addrs;
+
+ arr_class = (*env)->FindClass(env,"[I");
+ if (!arr_class)
+ return(_javanet_throw_exception(env, UNKNOWN_HOST_EXCEPTION,
+ "Internal Error"));
+
+ addrs = (*env)->NewObjectArray(env, num_addrs, arr_class, 0);
+ if (!addrs)
+ return(_javanet_throw_exception(env, UNKNOWN_HOST_EXCEPTION,
+ "Internal Error"));
+
+ /* Now loop and copy in each address */
+ for (i = 0; i < num_addrs; i++)
+ {
+ ret_octets = (*env)->NewIntArray(env, 4);
+ if (!ret_octets)
+ return(_javanet_throw_exception(env, UNKNOWN_HOST_EXCEPTION,
+ "Internal Error"));
+
+ octets = (*env)->GetIntArrayElements(env, ret_octets, 0);
+
+ ip = ntohl(*(int*)(hp->h_addr_list[i]));
+ octets[0] = (ip & 0xFF000000) >> 24;
+ octets[1] = (ip & 0x00FF0000) >> 16;
+ octets[2] = (ip & 0x0000FF00) >> 8;
+ octets[3] = (ip & 0x000000FF);
+
+ (*env)->ReleaseIntArrayElements(env, ret_octets, octets, 0);
+ (*env)->SetObjectArrayElement(env, addrs, i, ret_octets);
+ }
+
+ return(addrs);
+}
+
+
diff --git a/native/java.net/Makefile.am b/native/java.net/Makefile.am
new file mode 100644
index 000000000..a4864abbd
--- /dev/null
+++ b/native/java.net/Makefile.am
@@ -0,0 +1,39 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+lib_LTLIBRARIES = libjaphar_javanet.la
+
+libjaphar_javanet_la_SOURCES = InetAddress.c PlainDatagramSocketImpl.c \
+ PlainSocketImpl.c javanet.c javanet.h
+
+libjaphar_javanet_la_LDFLAGS = -version-info 0:0:0
+
+INCLUDES += -I$(prefix)/include -I$(prefix)/include/japhar
+
+InetAddress.c: java_net_InetAddress.h java_net_InetAddress_stubs.c
+
+PlainDatagramSocketImpl.c: java_net_PlainDatagramSocketImpl.h \
+ java_net_PlainDatagramSocketImpl_stubs.c
+
+PlainSocketImpl.c: java_net_PlainSocketImpl.h java_net_PlainSocketImpl_stubs.c
+
+# How to build stubs
+# How to build JNI *.h files
+
+java_net_InetAddress_stubs.c:
+ japharh -classpath ../.. -stubs -d $(srcdir) java.net.InetAddress
+
+java_net_InetAddress.h:
+ javah -jni -d $(srcdir) java.net.InetAddress
+
+java_net_PlainDatagramSocketImpl_stubs.c:
+ japharh -classpath ../.. -stubs -d $(srcdir) java.net.PlainDatagramSocketImpl
+
+java_net_PlainDatagramSocketImpl.h:
+ javah -jni -d $(srcdir) java.net.PlainDatagramSocketImpl
+
+java_net_PlainSocketImpl_stubs.c:
+ japharh -classpath ../.. -stubs -d $(srcdir) java.net.PlainSocketImpl
+
+java_net_PlainSocketImpl.h:
+ javah -jni -d $(srcdir) java.net.PlainSocketImpl
+
diff --git a/native/java.net/PlainDatagramSocketImpl.c b/native/java.net/PlainDatagramSocketImpl.c
new file mode 100644
index 000000000..e2497dca7
--- /dev/null
+++ b/native/java.net/PlainDatagramSocketImpl.c
@@ -0,0 +1,258 @@
+/*************************************************************************
+ * PlainDatagramSocketImpl.c - Native methods for PlainDatagramSocketImpl class
+ *
+ * Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation, version 2. (see COPYING.LIB)
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+ *************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <jni.h>
+
+#include "java_net_PlainDatagramSocketImpl.h"
+#include "java_net_PlainDatagramSocketImpl_stubs.c"
+
+#include "javanet.h"
+
+/*
+ * Note that most of the functions in this module simply redirect to another
+ * internal function. Why? Because many of these functions are shared
+ * with PlainSocketImpl.
+ */
+
+/*************************************************************************/
+
+/*
+ * Creates a new datagram socket
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainDatagramSocketImpl_create(JNIEnv *env, jobject this)
+{
+ _javanet_create(env, this, 0);
+}
+
+/*************************************************************************/
+
+/*
+ * Close the socket.
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainDatagramSocketImpl_close(JNIEnv *env, jobject this)
+{
+ _javanet_close(env, this, 0);
+}
+
+/*************************************************************************/
+
+/*
+ * This method binds the specified address to the specified local port.
+ * Note that we have to set the local address and local port public instance
+ * variables.
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainDatagramSocketImpl_bind(JNIEnv *env, jobject this,
+ jint port, jobject addr)
+{
+ _javanet_bind(env, this, addr, port, 0);
+}
+
+/*************************************************************************/
+
+/*
+ * This method sets the specified option for a socket
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainDatagramSocketImpl_setOption(JNIEnv *env, jobject this,
+ jint option_id, jobject val)
+{
+ _javanet_set_option(env, this, option_id, val);
+}
+
+/*************************************************************************/
+
+/*
+ * This method sets the specified option for a socket
+ */
+JNIEXPORT jobject JNICALL
+Java_java_net_PlainDatagramSocketImpl_getOption(JNIEnv *env, jobject this,
+ jint option_id)
+{
+ return(_javanet_get_option(env, this, option_id));
+}
+
+/*************************************************************************/
+
+/*
+ * Reads a buffer from a remote host
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainDatagramSocketImpl_receive(JNIEnv *env, jobject this,
+ jobject packet)
+{
+ unsigned int addr = 0, port = 0, len = 0, bytes_read = 0;
+ jclass cls, addr_cls;
+ jmethodID mid;
+ jarray arr;
+ jbyte *buf;
+ char ip_str[16];
+ jobject ip_str_obj, addr_obj;
+
+ /* Get the buffer from the packet */
+ cls = (*env)->GetObjectClass(env, packet);
+ mid = (*env)->GetMethodID(env, cls, "getData", "()[B");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+
+ arr = (*env)->CallObjectMethod(env, packet, mid);
+ if (!arr)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+
+ /* Now get the length from the packet */
+ mid = (*env)->GetMethodID(env, cls, "getLength", "()I");
+ if (!mid)
+ {
+ (*env)->ReleaseByteArrayElements(env, arr, buf, 0);
+ _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error");
+ return;
+ }
+ len = (*env)->CallIntMethod(env, packet, mid);
+ DBG("Got the length\n");
+
+ /* Receive the packet */
+ /* should we try some sort of validation on the length? */
+ bytes_read = _javanet_recvfrom(env, this, arr, 0, len, &addr, &port);
+ if (bytes_read == -1)
+ {
+ /* Taking a chance here because there is a pending exception */
+ (*env)->ReleaseByteArrayElements(env, arr, buf, 0);
+ return;
+ }
+ DBG("Received packet\n");
+
+ /* Store the address */
+ addr = ntohl(addr);
+ sprintf(ip_str, "%d.%d.%d.%d", (addr & 0xFF000000) >> 24,
+ (addr & 0x00FF0000) >> 16, (addr & 0x0000FF00) >> 8,
+ (addr & 0x000000FF));
+ ip_str_obj = (*env)->NewStringUTF(env, ip_str);
+
+ addr_cls = (*env)->FindClass(env, "java/net/InetAddress");
+ if (!addr_cls)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+ DBG("Found InetAddress class\n");
+
+ mid = (*env)->GetStaticMethodID(env, addr_cls, "getByName",
+ "(Ljava/lang/String;)Ljava/net/InetAddress;");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+ DBG("Found InetAddress.getByName method\n");
+
+ addr_obj = (*env)->CallStaticObjectMethod(env, addr_cls, mid, ip_str_obj);
+
+ mid = (*env)->GetMethodID(env, cls, "setAddress",
+ "(Ljava/net/InetAddress;)V");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+ (*env)->CallVoidMethod(env, packet, mid, addr_obj);
+ DBG("Stored the address\n");
+
+ /* Store the port */
+ port = ntohs(((unsigned short)port));
+
+ mid = (*env)->GetMethodID(env, cls, "setPort", "(I)V");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+
+ (*env)->CallVoidMethod(env, packet, mid, port);
+ DBG("Stored the port\n");
+
+ /* Store back the length */
+ mid = (*env)->GetMethodID(env, cls, "setLength", "(I)V");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+
+ (*env)->CallVoidMethod(env, packet, mid, bytes_read);
+ DBG("Stored the length\n");
+
+ return;
+}
+
+/*************************************************************************/
+
+/*
+ * Writes a buffer to the remote host
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainDatagramSocketImpl_sendto(JNIEnv *env, jobject this,
+ jobject addr, jint port, jarray buf,
+ jint len)
+{
+ _javanet_sendto(env, this, buf, 0, len, _javanet_get_netaddr(env, addr),
+ htons(((unsigned short)port)));
+}
+
+/*************************************************************************/
+
+/*
+ * Joins a multicast group
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainDatagramSocketImpl_join(JNIEnv *env, jobject this,
+ jobject addr)
+{
+ int rc;
+ struct ip_mreq ipm;
+
+ memset(&ipm, 0, sizeof(ipm));
+ ipm.imr_multiaddr.s_addr = _javanet_get_netaddr(env, addr);
+ ipm.imr_interface.s_addr = INADDR_ANY;
+
+ rc = setsockopt(_javanet_get_int_field(env, this, "native_fd"),
+ SOL_IP, IP_ADD_MEMBERSHIP, &ipm, sizeof(ipm));
+
+ if (rc == -1)
+ _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno));
+}
+
+/*************************************************************************/
+
+/*
+ * Leaves a multicast group
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainDatagramSocketImpl_leave(JNIEnv *env, jobject this,
+ jobject addr)
+{
+ int rc;
+ struct ip_mreq ipm;
+
+ memset(&ipm, 0, sizeof(ipm));
+ ipm.imr_multiaddr.s_addr = _javanet_get_netaddr(env, addr);
+ ipm.imr_interface.s_addr = INADDR_ANY;
+
+ rc = setsockopt(_javanet_get_int_field(env, this, "native_fd"),
+ SOL_IP, IP_DROP_MEMBERSHIP, &ipm, sizeof(ipm));
+
+ if (rc == -1)
+ _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno));
+}
+
+
diff --git a/native/java.net/PlainSocketImpl.c b/native/java.net/PlainSocketImpl.c
new file mode 100644
index 000000000..685e1dafe
--- /dev/null
+++ b/native/java.net/PlainSocketImpl.c
@@ -0,0 +1,154 @@
+/*************************************************************************
+ * PlainSocketImpl.c - Native methods for PlainSocketImpl class
+ *
+ * Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation, version 2. (see COPYING.LIB)
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+ *************************************************************************/
+
+#include <jni.h>
+
+#include "java_net_PlainSocketImpl.h"
+#include "java_net_PlainSocketImpl_stubs.c"
+
+#include "javanet.h"
+
+/*
+ * Note that the functions in this module simply redirect to another
+ * internal function. Why? Because many of these functions are shared
+ * with PlainDatagramSocketImpl. The unshared ones were done the same
+ * way for consistency.
+ */
+
+/*************************************************************************/
+
+/*
+ * Creates a new stream or datagram socket
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainSocketImpl_create(JNIEnv *env, jobject this, jboolean stream)
+{
+ _javanet_create(env, this, stream);
+}
+
+/*************************************************************************/
+
+/*
+ * Close the socket. Any underlying streams will be closed by this
+ * action as well.
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainSocketImpl_close(JNIEnv *env, jobject this)
+{
+ _javanet_close(env, this, 1);
+}
+
+/*************************************************************************/
+
+/*
+ * Connects to the specified destination.
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainSocketImpl_connect(JNIEnv *env, jobject this,
+ jobject addr, jint port)
+{
+ _javanet_connect(env, this, addr, port);
+}
+
+/*************************************************************************/
+
+/*
+ * This method binds the specified address to the specified local port.
+ * Note that we have to set the local address and local port public instance
+ * variables.
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainSocketImpl_bind(JNIEnv *env, jobject this, jobject addr,
+ jint port)
+{
+ _javanet_bind(env, this, addr, port, 1);
+}
+
+/*************************************************************************/
+
+/*
+ * Starts listening on a socket with the specified number of pending
+ * connections allowed.
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainSocketImpl_listen(JNIEnv *env, jobject this, jint queuelen)
+{
+ _javanet_listen(env, this, queuelen);
+}
+
+/*************************************************************************/
+
+/*
+ * Accepts a new connection and assigns it to the passed in SocketImpl
+ * object. Note that we assume this is a PlainSocketImpl just like us.
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainSocketImpl_accept(JNIEnv *env, jobject this, jobject impl)
+{
+ _javanet_accept(env, this, impl);
+}
+
+/*************************************************************************/
+
+/*
+ * This method sets the specified option for a socket
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainSocketImpl_setOption(JNIEnv *env, jobject this,
+ jint option_id, jobject val)
+{
+ _javanet_set_option(env, this, option_id, val);
+}
+
+/*************************************************************************/
+
+/*
+ * This method sets the specified option for a socket
+ */
+JNIEXPORT jobject JNICALL
+Java_java_net_PlainSocketImpl_getOption(JNIEnv *env, jobject this,
+ jint option_id)
+{
+ return(_javanet_get_option(env, this, option_id));
+}
+
+/*************************************************************************/
+
+/*
+ * Reads a buffer from a remote host
+ */
+JNIEXPORT jint JNICALL
+Java_java_net_PlainSocketImpl_read(JNIEnv *env, jobject this, jarray buf,
+ jint offset, jint len)
+{
+ return(_javanet_recvfrom(env, this, buf, offset, len, 0, 0));
+}
+
+/*************************************************************************/
+
+/*
+ * Writes a buffer to the remote host
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainSocketImpl_write(JNIEnv *env, jobject this, jarray buf,
+ jint offset, jint len)
+{
+ _javanet_sendto(env, this, buf, offset, len, 0, 0);
+}
+
diff --git a/native/java.net/javanet.c b/native/java.net/javanet.c
new file mode 100644
index 000000000..f1a5965a5
--- /dev/null
+++ b/native/java.net/javanet.c
@@ -0,0 +1,1012 @@
+/*************************************************************************
+ * javanet.c - Common internal functions for the java.net package
+ *
+ * Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation, version 2. (see COPYING.LIB)
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+ *************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <jni.h>
+
+#include "javanet.h"
+
+/* Need to have some value for SO_TIMEOUT */
+#ifndef SO_TIMEOUT
+#ifndef SO_RCVTIMEO
+#warning Neither SO_TIMEOUT or SO_RCVTIMEO are defined!
+#warning This will cause all get/setOption calls with that value to throw an exception
+#else
+#define SO_TIMEOUT SO_RCVTIMEO
+#endif /* not SO_RCVTIMEO */
+#endif /* not SO_TIMEOUT */
+
+/*************************************************************************/
+
+/*
+ * This is a common function to throw exceptions.
+ */
+int
+_javanet_throw_exception(JNIEnv *env, const char *exception, const char *msg)
+{
+ jclass ecls;
+
+ /* Find our exception class */
+ ecls = (*env)->FindClass(env, exception);
+ if (!ecls)
+ return(0);
+
+ /* Clean any pending exceptions */
+ if ((*env)->ExceptionOccurred(env))
+ (*env)->ExceptionClear(env);
+
+ /* Throw the exception and return */
+ (*env)->ThrowNew(env, ecls, msg);
+
+ return(0);
+}
+
+/*************************************************************************/
+
+/*
+ * Sets an integer field in the specified object.
+ */
+static void
+_javanet_set_int_field(JNIEnv *env, jobject obj, char *class, char *field,
+ int val)
+{
+ jclass cls;
+ jfieldID fid;
+
+ cls = (*env)->FindClass(env, class);
+ fid = (*env)->GetFieldID(env, cls, field, "I");
+ if (!fid)
+ return;
+
+ (*env)->SetIntField(env, obj, fid, val);
+
+ return;
+}
+
+/*************************************************************************/
+
+/*
+ * Returns the value of the specified integer instance variable field or
+ * -1 if an error occurs.
+ */
+int
+_javanet_get_int_field(JNIEnv *env, jobject obj, const char *field)
+{
+ jclass cls = 0;
+ jfieldID fid;
+ int fd;
+
+ DBG("Entered _javanet_get_int_field\n");
+
+ cls = (*env)->GetObjectClass(env, obj);
+ fid = (*env)->GetFieldID(env, cls, field, "I");
+ if (!fid)
+ return(-1);
+ DBG("Found field id\n");
+
+ fd = (*env)->GetIntField(env, obj, fid);
+
+ return(fd);
+}
+
+/*************************************************************************/
+
+/*
+ * Creates a FileDescriptor object in the parent class. It is not used
+ * by this implementation, but the docs list it as a variable, so we
+ * need to include it.
+ */
+static void
+_javanet_create_localfd(JNIEnv *env, jobject this)
+{
+ jclass this_cls, fd_cls;
+ jfieldID fid;
+ jmethodID mid;
+ jobject fd_obj;
+
+ DBG("Entered _javanet_create_localfd\n");
+
+ /* Look up the fd field */
+ this_cls = (*env)->FindClass(env, "java/net/SocketImpl");
+ fid = (*env)->GetFieldID(env, this_cls, "fd", "Ljava/io/FileDescriptor;");
+ if (!fid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+ DBG("Found fd variable\n");
+
+ /* Create a FileDescriptor */
+ fd_cls = (*env)->FindClass(env, "java/io/FileDescriptor");
+ if (!fd_cls)
+ {
+ _javanet_throw_exception(env, IO_EXCEPTION, "Can't load FileDescriptor class");
+ return;
+ }
+ DBG("Found FileDescriptor class\n");
+
+ mid = (*env)->GetMethodID(env, fd_cls, "<init>", "()V");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+ DBG("Found FileDescriptor constructor\n");
+
+ fd_obj = (*env)->NewObject(env, fd_cls, mid);
+ if (!fd_obj)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+ DBG("Created FileDescriptor\n");
+
+ /* Now set the pointer to the new FileDescriptor */
+ (*env)->SetObjectField(env, this, fid, fd_obj);
+ DBG("Set fd field\n");
+
+ return;
+}
+
+/*************************************************************************/
+
+/*
+ * Returns a Boolean object with the specfied value
+ */
+static jobject
+_javanet_create_boolean(JNIEnv *env, jboolean val)
+{
+ jclass cls;
+ jmethodID mid;
+ jobject obj;
+
+ cls = (*env)->FindClass(env, "java/lang/Boolean");
+ if (!cls)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return(0); }
+
+ mid = (*env)->GetMethodID(env, cls, "<init>", "(Z)V");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return(0); }
+
+ obj = (*env)->NewObject(env, cls, mid, val);
+ if (!obj)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return(0); }
+
+ return(obj);
+}
+
+/*************************************************************************/
+
+/*
+ * Returns an Integer object with the specfied value
+ */
+static jobject
+_javanet_create_integer(JNIEnv *env, jint val)
+{
+ jclass cls;
+ jmethodID mid;
+ jobject obj;
+
+ cls = (*env)->FindClass(env, "java/lang/Integer");
+ if (!cls)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return(0); }
+
+ mid = (*env)->GetMethodID(env, cls, "<init>", "(I)V");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return(0); }
+
+ obj = (*env)->NewObject(env, cls, mid, val);
+ if (!obj)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return(0); }
+
+ return(obj);
+}
+
+/*************************************************************************/
+
+/*
+ * Builds an InetAddress object from a 32 bit address in host byte order
+ */
+static jobject
+_javanet_create_inetaddress(JNIEnv *env, int netaddr)
+{
+ char buf[16];
+ jclass ia_cls;
+ jmethodID mid;
+ jstring ip_str;
+ jobject ia;
+
+ /* Build a string IP address */
+ sprintf(buf, "%d.%d.%d.%d", ((netaddr & 0xFF000000) >> 24),
+ ((netaddr & 0x00FF0000) >> 16), ((netaddr &0x0000FF00) >> 8),
+ (netaddr & 0x000000FF));
+ DBG("Created ip addr string\n");
+
+ /* Get an InetAddress object for this IP */
+ ia_cls = (*env)->FindClass(env, "java/net/InetAddress");
+ if (!ia_cls)
+ {
+ _javanet_throw_exception(env, IO_EXCEPTION, "Can't load InetAddress class");
+ return(0);
+ }
+ DBG("Found InetAddress class\n");
+
+ mid = (*env)->GetStaticMethodID(env, ia_cls, "getByName",
+ "(Ljava/lang/String;)Ljava/net/InetAddress;");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return(0); }
+ DBG("Found getByName method\n");
+
+ ip_str = (*env)->NewStringUTF(env, buf);
+ if (!ip_str)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return(0); }
+
+ ia = (*env)->CallStaticObjectMethod(env, ia_cls, mid, ip_str);
+ if (!ia)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return(0); }
+ DBG("Called getByName method\n");
+
+ return(ia);
+}
+
+/*************************************************************************/
+
+/*
+ * Set's the value of the "addr" field in PlainSocketImpl with a new
+ * InetAddress for the specified addr
+ */
+static void
+_javanet_set_remhost(JNIEnv *env, jobject this, int netaddr)
+{
+ jclass this_cls;
+ jfieldID fid;
+ jobject ia;
+
+ DBG("Entered _javanet_set_remhost\n");
+
+ /* Get an InetAddress object */
+ ia = _javanet_create_inetaddress(env, netaddr);
+ if (!ia)
+ return;
+
+ /* Set the variable in the object */
+ this_cls = (*env)->FindClass(env, "java/net/SocketImpl");
+ fid = (*env)->GetFieldID(env, this_cls, "address", "Ljava/net/InetAddress;");
+ if (!fid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+ DBG("Found address field\n");
+
+ (*env)->SetObjectField(env, this, fid, ia);
+ DBG("Set field\n");
+}
+
+/*************************************************************************/
+
+/*
+ * Returns a 32 bit Internet address for the passed in InetAddress object
+ */
+int
+_javanet_get_netaddr(JNIEnv *env, jobject addr)
+{
+ jclass cls = 0;
+ jmethodID mid;
+ jarray arr = 0;
+ jbyte *octets;
+ int netaddr, len;
+
+ DBG("Entered _javanet_get_netaddr\n");
+
+ /* Call the getAddress method on the object to retrieve the IP address */
+ cls = (*env)->GetObjectClass(env, addr);
+ mid = (*env)->GetMethodID(env, cls, "getAddress", "()[B");
+ if (!mid)
+ return(_javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"));
+ DBG("Got getAddress method\n");
+
+ arr = (*env)->CallObjectMethod(env, addr, mid);
+ if (!arr)
+ return(_javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"));
+ DBG("Got the address\n");
+
+ /* Turn the IP address into a 32 bit Internet address in network byte order */
+ len = (*env)->GetArrayLength(env, arr);
+ if (len != 4)
+ return(_javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"));
+ DBG("Length ok\n");
+
+ octets = (*env)->GetByteArrayElements(env, arr, 0);
+ if (!octets)
+ return(_javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"));
+ DBG("Grabbed bytes\n");
+
+ netaddr = (((unsigned char)octets[0]) << 24) +
+ (((unsigned char)octets[1]) << 16) +
+ (((unsigned char)octets[2]) << 8) +
+ ((unsigned char)octets[3]);
+
+ netaddr = htonl(netaddr);
+
+ (*env)->ReleaseByteArrayElements(env, arr, octets, 0);
+ DBG("Done getting addr\n");
+
+ return(netaddr);
+}
+
+/*************************************************************************/
+
+/*
+ * Creates a new stream or datagram socket
+ */
+void
+_javanet_create(JNIEnv *env, jobject this, jboolean stream)
+{
+ int fd;
+
+ if (stream)
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ else
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ if (fd == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno)); return; }
+
+ if (stream)
+ _javanet_set_int_field(env, this, "java/net/PlainSocketImpl",
+ "native_fd", fd);
+ else
+ _javanet_set_int_field(env, this, "java/net/PlainDatagramSocketImpl",
+ "native_fd", fd);
+}
+
+/*************************************************************************/
+
+/*
+ * Close the socket. Any underlying streams will be closed by this
+ * action as well.
+ */
+void
+_javanet_close(JNIEnv *env, jobject this, int stream)
+{
+ int fd = -1;
+
+ fd = _javanet_get_int_field(env, this, "native_fd");
+ if (fd == -1)
+ return;
+
+ close(fd);
+
+ if (stream)
+ _javanet_set_int_field(env, this, "java/net/PlainSocketImpl",
+ "native_fd", -1);
+ else
+ _javanet_set_int_field(env, this, "java/net/PlainDatagramSocketImpl",
+ "native_fd", -1);
+}
+
+/*************************************************************************/
+
+/*
+ * Connects to the specified destination.
+ */
+void
+_javanet_connect(JNIEnv *env, jobject this, jobject addr, jint port)
+{
+ int netaddr, fd = -1, rc, addrlen;
+ struct sockaddr_in si;
+
+ DBG("Entered _javanet_connect\n");
+
+ /* Pre-process input variables */
+ netaddr = _javanet_get_netaddr(env, addr);
+ if ((*env)->ExceptionOccurred(env))
+ return;
+
+ if (port == -1)
+ port = 0;
+ DBG("Got network address\n");
+
+ /* Grab the real socket file descriptor */
+ fd = _javanet_get_int_field(env, this, "native_fd");
+ if (fd == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION,
+ "Socket not yet created"); return; }
+ DBG("Got native fd\n");
+
+ /* Connect up */
+ memset(&si, 0, sizeof(struct sockaddr_in));
+ si.sin_family = AF_INET;
+ si.sin_addr.s_addr = netaddr;
+ si.sin_port = htons(((short)port));
+
+ rc = connect(fd, &si, sizeof(struct sockaddr_in));
+ if (rc == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno)); return; }
+ DBG("Connected successfully\n");
+
+ /* Populate instance variables */
+ addrlen = sizeof(struct sockaddr_in);
+ rc = getsockname(fd, &si, &addrlen);
+ if (rc == -1)
+ {
+ close(fd);
+ _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno));
+ return;
+ }
+
+ _javanet_create_localfd(env, this);
+ if ((*env)->ExceptionOccurred(env))
+ return;
+ DBG("Created fd\n");
+
+ _javanet_set_int_field(env, this, "java/net/SocketImpl", "localport",
+ ntohs(si.sin_port));
+ if ((*env)->ExceptionOccurred(env))
+ return;
+ DBG("Set the local port\n");
+
+ addrlen = sizeof(struct sockaddr_in);
+ rc = getpeername(fd, &si, &addrlen);
+ if (rc == -1)
+ {
+ close(fd);
+ _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno));
+ return;
+ }
+
+ _javanet_set_remhost(env, this, ntohl(si.sin_addr.s_addr));
+ if ((*env)->ExceptionOccurred(env))
+ return;
+ DBG("Set the remote host\n");
+
+ _javanet_set_int_field(env, this, "java/net/SocketImpl", "port",
+ ntohs(si.sin_port));
+ if ((*env)->ExceptionOccurred(env))
+ return;
+ DBG("Set the remote port\n");
+}
+
+/*************************************************************************/
+
+/*
+ * This method binds the specified address to the specified local port.
+ * Note that we have to set the local address and local
+ * port public instance variables.
+ */
+void
+_javanet_bind(JNIEnv *env, jobject this, jobject addr, jint port, int stream)
+{
+ jclass cls;
+ jmethodID mid;
+ jbyteArray arr = 0;
+ jbyte *octets;
+ jint fd;
+ struct sockaddr_in si;
+ int namelen;
+
+ DBG("Entering native bind()\n");
+
+ /* Get the address to connect to */
+ cls = (*env)->GetObjectClass(env, addr);
+ mid = (*env)->GetMethodID(env, cls, "getAddress", "()[B");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal error") ; return; }
+ DBG("Past getAddress method id\n");
+
+ arr = (*env)->CallObjectMethod(env, addr, mid);
+ if (!arr || (*env)->ExceptionOccurred(env))
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal error") ; return; }
+ DBG("Past call object method\n");
+
+ octets = (*env)->GetByteArrayElements(env, arr, 0);
+ if (!octets)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal error") ; return; }
+ DBG("Past grab array\n");
+
+ /* Get the native socket file descriptor */
+ fd = _javanet_get_int_field(env, this, "native_fd");
+ if (fd == -1)
+ {
+ (*env)->ReleaseByteArrayElements(env, arr, octets, 0);
+ _javanet_throw_exception(env, IO_EXCEPTION, "Internal error");
+ return;
+ }
+ DBG("Past native_fd lookup\n");
+
+ /* Bind the socket */
+ memset(&si, 0, sizeof(struct sockaddr_in));
+
+ si.sin_family = AF_INET;
+ si.sin_addr.s_addr = *(int *)octets; /* Already in network byte order */
+ if (port == -1)
+ si.sin_port = 0;
+ else
+ si.sin_port = htons(port);
+
+ (*env)->ReleaseByteArrayElements(env, arr, octets, 0);
+
+ if (bind(fd, &si, sizeof(struct sockaddr_in)) == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno)); return; }
+ DBG("Past bind\n");
+
+ /* Update instance variables, specifically the local port number */
+ namelen = sizeof(struct sockaddr_in);
+ getsockname(fd, &si, &namelen);
+
+ if (stream)
+ _javanet_set_int_field(env, this, "java/net/SocketImpl",
+ "localport", ntohs(si.sin_port));
+ else
+ _javanet_set_int_field(env, this, "java/net/DatagramSocketImpl",
+ "localPort", ntohs(si.sin_port));
+ DBG("Past update port number\n");
+
+ return;
+}
+
+/*************************************************************************/
+
+/*
+ * Starts listening on a socket with the specified number of pending
+ * connections allowed.
+ */
+void
+_javanet_listen(JNIEnv *env, jobject this, jint queuelen)
+{
+ int fd = -1, rc;
+
+ /* Get the real file descriptor */
+ fd = _javanet_get_int_field(env, this, "native_fd");
+ if (fd == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION,
+ "Internal Error"); return; }
+
+ /* Start listening */
+ rc = listen(fd, queuelen);
+ if (rc == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno)); return; }
+
+ return;
+}
+
+/*************************************************************************/
+
+/*
+ * Accepts a new connection and assigns it to the passed in SocketImpl
+ * object. Note that we assume this is a PlainSocketImpl just like us
+ */
+void
+_javanet_accept(JNIEnv *env, jobject this, jobject impl)
+{
+ int fd = -1, newfd, addrlen, rc;
+ struct sockaddr_in si;
+
+ /* Get the real file descriptor */
+ fd = _javanet_get_int_field(env, this, "native_fd");
+ if (fd == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+
+ /* Accept the connection */
+ addrlen = sizeof(struct sockaddr_in);
+ memset(&si, 0, addrlen);
+
+ /******* Do we need to look for EINTR? */
+ newfd = accept(fd, &si, &addrlen);
+ if (newfd == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+
+ /* Populate instance variables */
+ _javanet_set_int_field(env, impl, "java/net/PlainSocketImpl", "native_fd",
+ newfd);
+
+ rc = getsockname(newfd, &si, &addrlen);
+ if (rc == -1)
+ {
+ close(newfd);
+ _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno));
+ return;
+ }
+
+ _javanet_create_localfd(env, impl);
+ if ((*env)->ExceptionOccurred(env))
+ return;
+
+ _javanet_set_int_field(env, impl, "java/net/SocketImpl", "localport",
+ ntohs(si.sin_port));
+ if ((*env)->ExceptionOccurred(env))
+ return;
+
+ addrlen = sizeof(struct sockaddr_in);
+ rc = getpeername(newfd, &si, &addrlen);
+ if (rc == -1)
+ {
+ close(newfd);
+ _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno));
+ return;
+ }
+
+ _javanet_set_remhost(env, impl, ntohl(si.sin_addr.s_addr));
+ if ((*env)->ExceptionOccurred(env))
+ return;
+
+ _javanet_set_int_field(env, impl, "java/net/SocketImpl", "port",
+ ntohs(si.sin_port));
+ if ((*env)->ExceptionOccurred(env))
+ return;
+}
+
+/*************************************************************************/
+
+/*
+ * Receives a buffer from a remote host. The args are:
+ *
+ * buf - The byte array into which the data received will be written
+ * offset - Offset into the byte array to start writing
+ * len - The number of bytes to read.
+ * addr - Pointer to 32 bit net address of host to receive from. If null,
+ * this parm is ignored. If pointing to an address of 0, the
+ * actual address read is stored here
+ * port - Pointer to the port to receive from. If null, this parm is ignored.
+ * If it is 0, the actual remote port received from is stored here
+ *
+ * The actual number of bytes read is returned.
+ */
+int
+_javanet_recvfrom(JNIEnv *env, jobject this, jarray buf, int offset, int len,
+ int *addr, int *port)
+{
+ int fd, rc, si_len;
+ jbyte *p;
+ struct sockaddr_in si;
+
+ DBG("Entered _javanet_recvfrom\n");
+
+ /* Get the real file descriptor */
+ fd = _javanet_get_int_field(env, this, "native_fd");
+ if (fd == -1)
+ { return(_javanet_throw_exception(env, IO_EXCEPTION, "No Socket")); }
+ DBG("Got native_fd\n");
+
+ /* Get a pointer to the buffer */
+ p = (*env)->GetByteArrayElements(env, buf, 0);
+ if (!p)
+ { return(_javanet_throw_exception(env, IO_EXCEPTION, "Internal Error")); }
+ DBG("Got buffer\n");
+
+ /* Read the data */
+ for (;;)
+ {
+ if (!addr)
+ rc = recvfrom(fd, p + offset, len, 0, 0, 0);
+ else
+ {
+ memset(&si, 0, sizeof(struct sockaddr_in));
+ si_len = sizeof(struct sockaddr_in);
+ rc = recvfrom(fd, p + offset, len, 0, &si, &si_len);
+ }
+
+ if ((rc == -1) && (errno == EINTR))
+ continue;
+
+ break;
+ }
+
+ (*env)->ReleaseByteArrayElements(env, buf, p, 0);
+
+ if (rc == -1)
+ { return(_javanet_throw_exception(env, IO_EXCEPTION, strerror(errno))); }
+
+ /* Handle return addr case */
+ if (addr)
+ {
+ *addr = si.sin_addr.s_addr;
+ if (port)
+ *port = si.sin_port;
+ }
+
+ return(rc);
+}
+
+/*************************************************************************/
+
+/*
+ * Sends a buffer to a remote host. The args are:
+ *
+ * buf - A byte array
+ * offset - Index into the byte array to start sendign
+ * len - The number of bytes to write
+ * addr - The 32bit address to send to (may be 0)
+ * port - The port number to send to (may be 0)
+ */
+void
+_javanet_sendto(JNIEnv *env, jobject this, jarray buf, int offset, int len,
+ int addr, int port)
+{
+ int fd, rc;
+ jbyte *p;
+ struct sockaddr_in si;
+
+ /* Get the real file descriptor */
+ fd = _javanet_get_int_field(env, this, "native_fd");
+ if (fd == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "No Socket"); return; }
+
+ /* Get a pointer to the buffer */
+ p = (*env)->GetByteArrayElements(env, buf, 0);
+ if (!p)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+
+ /* Send the data */
+ if (!addr)
+ rc = send(fd, p + offset, len, 0);
+ else
+ {
+ memset(&si, 0, sizeof(struct sockaddr_in));
+ si.sin_family = AF_INET;
+ si.sin_addr.s_addr = addr;
+ si.sin_port = (unsigned short)port;
+
+ DBG("Sending....\n");
+ rc = sendto(fd, p + offset, len, 0, &si, sizeof(struct sockaddr_in));
+ }
+
+ (*env)->ReleaseByteArrayElements(env, buf, p, 0);
+
+ /***** Do we need to check EINTR? */
+ if (rc == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION, strerror(errno)); return; }
+
+ return;
+}
+
+/*************************************************************************/
+
+/*
+ * Sets the specified option for a socket
+ */
+void
+_javanet_set_option(JNIEnv *env, jobject this, jint option_id, jobject val)
+{
+ int fd = -1, rc;
+ int optval;
+ jclass cls;
+ jmethodID mid;
+ struct linger linger;
+ struct sockaddr_in si;
+
+ /* Get the real file descriptor */
+ fd = _javanet_get_int_field(env, this, "native_fd");
+ if (fd == -1)
+ { _javanet_throw_exception(env, IO_EXCEPTION, "Internal Error"); return; }
+
+ /* We need a class object for all cases below */
+ cls = (*env)->GetObjectClass(env, val);
+
+ /* Process the option request */
+ switch (option_id)
+ {
+ /* TCP_NODELAY case. val is a Boolean that tells us what to do */
+ case SOCKOPT_TCP_NODELAY:
+ mid = (*env)->GetMethodID(env, cls, "booleanValue", "()Z");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION,
+ "Internal Error"); return; }
+
+ /* Should be a 0 or a 1 */
+ optval = (*env)->CallBooleanMethod(env, val, mid);
+
+ rc = setsockopt(fd, SOL_TCP, TCP_NODELAY, &optval, sizeof(int));
+ break;
+
+ /* SO_LINGER case. If val is a boolean, then it will always be set
+ to false indicating disable linger, otherwise it will be an
+ integer that contains the linger value */
+ case SOCKOPT_SO_LINGER:
+ memset(&linger, 0, sizeof(struct linger));
+
+ mid = (*env)->GetMethodID(env, cls, "booleanValue", "()Z");
+ if (mid)
+ {
+ /* We are disabling linger */
+ linger.l_onoff = 0;
+ }
+ else
+ {
+ mid = (*env)->GetMethodID(env, cls, "intValue", "()I");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION,
+ "Internal Error"); return; }
+
+ linger.l_linger = (*env)->CallIntMethod(env, val, mid);
+ linger.l_onoff = 1;
+ }
+ rc = setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger,
+ sizeof(struct linger));
+ break;
+
+ /* SO_TIMEOUT case. Val will be an integer with the new value */
+ case SOCKOPT_SO_TIMEOUT:
+#ifdef SO_TIMEOUT
+ mid = (*env)->GetMethodID(env, cls, "intValue", "()I");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION,
+ "Internal Error"); return; }
+
+ optval = (*env)->CallIntMethod(env, val, mid);
+
+ rc = setsockopt(fd, SOL_SOCKET, SO_TIMEOUT, &optval, sizeof(int));
+#else
+ _javanet_throw_exception(env, SOCKET_EXCEPTION,
+ "SO_TIMEOUT not supported on this platform");
+ return;
+#endif
+ break;
+
+ /* TTL case. Val with be an Integer with the new time to live value */
+ case SOCKOPT_IP_TTL:
+ mid = (*env)->GetMethodID(env, cls, "intValue", "()I");
+ if (!mid)
+ { _javanet_throw_exception(env, IO_EXCEPTION,
+ "Internal Error"); return; }
+
+ optval = (*env)->CallIntMethod(env, val, mid);
+
+ rc = setsockopt(fd, SOL_IP, IP_TTL, &optval, sizeof(int));
+ break;
+
+ /* Multicast Interface case - val is InetAddress object */
+ case SOCKOPT_IP_MULTICAST_IF:
+ memset(&si, 0, sizeof(struct sockaddr_in));
+ si.sin_family = AF_INET;
+ si.sin_addr.s_addr = _javanet_get_netaddr(env, val);
+
+ if ((*env)->ExceptionOccurred(env))
+ return;
+
+ rc = setsockopt(fd, SOL_IP, IP_MULTICAST_IF, &si,
+ sizeof(struct sockaddr_in));
+ break;
+
+ default:
+ _javanet_throw_exception(env, SOCKET_EXCEPTION, "Unrecognized option");
+ return;
+ }
+
+ /* Check to see if above operations succeeded */
+ if (rc == -1)
+ _javanet_throw_exception(env, SOCKET_EXCEPTION, strerror(errno));
+
+ return;
+}
+
+/*************************************************************************/
+
+/*
+ * Retrieves the specified option values for a socket
+ */
+jobject
+_javanet_get_option(JNIEnv *env, jobject this, jint option_id)
+{
+ int fd = -1, rc;
+ int optval, optlen;
+ struct linger linger;
+ struct sockaddr_in si;
+
+ /* Get the real file descriptor */
+ fd = _javanet_get_int_field(env, this, "native_fd");
+ if (fd == -1)
+ { _javanet_throw_exception(env, SOCKET_EXCEPTION, "Internal Error"); return(0); }
+
+ /* Process the option requested */
+ switch (option_id)
+ {
+ /* TCP_NODELAY case. Return a Boolean indicating on or off */
+ case SOCKOPT_TCP_NODELAY:
+ optlen = sizeof(optval);
+ rc = getsockopt(fd, SOL_TCP, TCP_NODELAY, &optval, &optlen);
+ if (rc == -1)
+ {
+ _javanet_throw_exception(env, SOCKET_EXCEPTION, strerror(errno));
+ return(0);
+ }
+
+ if (optval)
+ return(_javanet_create_boolean(env, 1));
+ else
+ return(_javanet_create_boolean(env, 0));
+
+ break;
+
+ /* SO_LINGER case. If disabled, return a Boolean object that represents
+ false, else return an Integer that is the value of SO_LINGER */
+ case SOCKOPT_SO_LINGER:
+ memset(&linger, 0, sizeof(struct linger));
+ optlen = sizeof(struct linger);
+
+ rc = getsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, &optlen);
+ if (rc == -1)
+ {
+ _javanet_throw_exception(env, SOCKET_EXCEPTION, strerror(errno));
+ return(0);
+ }
+
+ if (linger.l_onoff)
+ return(_javanet_create_integer(env, linger.l_linger));
+ else
+ return(_javanet_create_boolean(env, 0));
+
+ break;
+
+ /* SO_TIMEOUT case. Return an Integer object with the timeout value */
+ case SOCKOPT_SO_TIMEOUT:
+#ifdef SO_TIMEOUT
+ optlen = sizeof(int);
+
+ rc = getsockopt(fd, SOL_SOCKET, SO_TIMEOUT, &optval, &optlen);
+#else
+ _javanet_throw_exception(env, SOCKET_EXCEPTION,
+ "SO_TIMEOUT not supported on this platform");
+ return(0);
+#endif /* not SO_TIMEOUT */
+
+ if (rc == -1)
+ {
+ _javanet_throw_exception(env, SOCKET_EXCEPTION, strerror(errno));
+ return(0);
+ }
+
+ return(_javanet_create_integer(env, optval));
+ break;
+
+ /* The TTL case. Return an Integer with the Time to Live value */
+ case SOCKOPT_IP_TTL:
+ optlen = sizeof(int);
+
+ rc = getsockopt(fd, SOL_IP, IP_TTL, &optval, &optlen);
+ if (rc == -1)
+ {
+ _javanet_throw_exception(env, SOCKET_EXCEPTION, strerror(errno));
+ return(0);
+ }
+
+ return(_javanet_create_integer(env, optval));
+ break;
+
+ /* Multicast interface case */
+ case SOCKOPT_IP_MULTICAST_IF:
+ memset(&si, 0, sizeof(struct sockaddr_in));
+ optlen = sizeof(struct sockaddr_in);
+
+ rc = getsockopt(fd, SOL_IP, IP_MULTICAST_IF, &si, &optlen);
+ if (rc == -1)
+ {
+ _javanet_throw_exception(env, SOCKET_EXCEPTION, strerror(errno));
+ return(0);
+ }
+
+ return(_javanet_create_inetaddress(env, ntohl(si.sin_addr.s_addr)));
+ break;
+
+ default:
+ _javanet_throw_exception(env, SOCKET_EXCEPTION, strerror(errno));
+ return(0);
+ }
+
+ return(0);
+}
+
diff --git a/native/java.net/javanet.h b/native/java.net/javanet.h
new file mode 100644
index 000000000..cfc4b6b07
--- /dev/null
+++ b/native/java.net/javanet.h
@@ -0,0 +1,83 @@
+/*************************************************************************
+ * javanet.h - Declarations for common functions for the java.net package
+ *
+ * Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation, version 2. (see COPYING.LIB)
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
+ *************************************************************************/
+
+#ifndef _JAVANET_LOADED
+#define _JAVANET_LOADED
+
+#include <jni.h>
+
+/*************************************************************************/
+
+/*
+ * Defined constants
+ */
+
+/* Exception Classes */
+#define IO_EXCEPTION "java/io/IOException"
+#define SOCKET_EXCEPTION "java/net/SocketException"
+#define UNKNOWN_HOST_EXCEPTION "java/net/UnknownHostException"
+
+/* Socket Option Identifiers - Don't change or binary compatibility with
+ the JDK will be broken! These also need to
+ be kept compatible with java.net.SocketOptions */
+#define SOCKOPT_TCP_NODELAY 1
+#define SOCKOPT_SO_LINGER 128
+#define SOCKOPT_SO_TIMEOUT 4102
+
+/* Internal option identifiers. Not needed for JDK compatibility */
+#define SOCKOPT_IP_TTL 7777
+#define SOCKOPT_IP_MULTICAST_IF 7778
+
+/*************************************************************************/
+
+/*
+ * Macros
+ */
+
+/* Simple debug macro */
+#ifdef DEBUG
+#define DBG(x) fprintf(stderr, (x));
+#else
+#define DBG(x)
+#endif
+
+/*************************************************************************/
+
+/*
+ * Function Prototypes
+ */
+
+extern int _javanet_throw_exception(JNIEnv *, const char *, const char *);
+extern int _javanet_get_int_field(JNIEnv *, jobject, const char *);
+extern int _javanet_get_netaddr(JNIEnv *, jobject);
+extern void _javanet_create(JNIEnv *, jobject, jboolean);
+extern void _javanet_close(JNIEnv *, jobject, int);
+extern void _javanet_connect(JNIEnv *, jobject, jobject, jint);
+extern void _javanet_bind(JNIEnv *, jobject, jobject, jint, int);
+extern void _javanet_listen(JNIEnv *, jobject, jint);
+extern void _javanet_accept(JNIEnv *, jobject, jobject);
+extern int _javanet_recvfrom(JNIEnv *, jobject, jarray, int, int, int *, int *);
+extern void _javanet_sendto(JNIEnv *, jobject, jarray, int, int, int, int);
+extern jobject _javanet_get_option(JNIEnv *, jobject, jint);
+extern void _javanet_set_option(JNIEnv *, jobject, jint, jobject);
+
+/*************************************************************************/
+
+#endif /* not _JAVANET_H_LOADED */
+
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 000000000..1376de35c
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,4 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+SUBDIRS = java.net
+
diff --git a/test/java.net/ClientDatagram.java b/test/java.net/ClientDatagram.java
new file mode 100644
index 000000000..6ec98258e
--- /dev/null
+++ b/test/java.net/ClientDatagram.java
@@ -0,0 +1,112 @@
+/* Class to test Datagrams from a client perspective */
+
+import java.io.*;
+import java.net.*;
+
+public class ClientDatagram
+{
+
+public static void
+main(String[] argv) throws IOException
+{
+ System.out.println("Starting datagram tests");
+
+ byte[] buf = new byte[2048];
+ DatagramPacket p = new DatagramPacket(buf, buf.length);
+ InetAddress addr = InetAddress.getByName("localhost");
+
+ /* Execute the daytime UDP service on localhost. You may need to
+ enable this in inetd to make the test work */
+ System.out.println("Test 1: Simple daytime test");
+ try
+ {
+
+ DatagramSocket s = new DatagramSocket();
+
+ System.out.println("Socket bound to " + s.getLocalAddress() +
+ ":" + s.getLocalPort());
+
+ byte[] sbuf = { 'H', 'I' };
+ DatagramPacket spack = new DatagramPacket(sbuf, sbuf.length, addr, 13);
+
+ s.send(spack);
+ s.receive(p);
+
+ System.out.println("Received " + p.getLength() + " bytes from " +
+ p.getAddress() + ":" + p.getPort());
+
+ byte[] tmp = new byte[p.getLength()];
+ for (int i = 0; i < p.getLength(); i++)
+ tmp[i] = buf[i];
+
+ System.out.print("Data: " + new String(tmp));
+
+ s.close();
+ System.out.println("PASSED simple datagram test");
+ }
+ catch(Exception e)
+ {
+ System.out.println("FAILED simple datagram test: " + e);
+ }
+
+ System.out.println("Test 2: Specific host/port binding");
+ try
+ {
+ DatagramSocket s = new DatagramSocket(8765, addr);
+ if (s.getLocalPort() != 8765)
+ throw new IOException("Bound to wrong port: " + s.getLocalPort());
+
+ if (!s.getLocalAddress().equals(addr))
+ throw new IOException("Bound to wrong host:" + s.getLocalAddress());
+
+ s.close();
+ System.out.println("PASSED specific host/port binding test");
+ }
+ catch (Exception e)
+ {
+ System.out.println("FAILED specific host/port binding: " + e);
+ }
+
+ System.out.println("Test 3: Socket Options test");
+ try
+ {
+ DatagramSocket s = new DatagramSocket();
+ System.out.println("SO_TIMEOUT = " + s.getSoTimeout());
+ System.out.println("Setting SO_TIMEOUT to 170");
+ s.setSoTimeout(170);
+ System.out.println("SO_TIMEOUT = " + s.getSoTimeout());
+ System.out.println("Setting SO_TIMEOUT to 0");
+ s.setSoTimeout(0);
+ System.out.println("SO_TIMEOUT = " + s.getSoTimeout());
+ s.close();
+ }
+ catch(Exception e)
+ {
+ System.out.println("WARNING: Problem with SO_TIMEOUT test: " + e.getMessage());
+ System.out.println("This is ok on Linux");
+ }
+
+ System.out.println("Test 4: Max values test");
+ try
+ {
+// ServerDatagram sd = new ServerDatagram(37900);
+// sd.run();
+
+ DatagramSocket s = new DatagramSocket();
+ byte[] sbuf = new byte[65332];
+ DatagramPacket spack = new DatagramPacket(sbuf, sbuf.length,
+ addr, 37900);
+
+ s.send(spack);
+ s.close();
+ }
+ catch (Exception e)
+ {
+ System.out.println("FAILED max values test: " + e);
+ }
+
+ System.out.println("Datagram testing complete");
+}
+
+}
+
diff --git a/test/java.net/ClientSocket.java b/test/java.net/ClientSocket.java
new file mode 100644
index 000000000..53a498b34
--- /dev/null
+++ b/test/java.net/ClientSocket.java
@@ -0,0 +1,189 @@
+/* A class to test my client TCP socket implementation */
+
+import java.net.*;
+import java.io.*;
+
+public class ClientSocket extends Object
+{
+public static void
+main(String[] argv) throws IOException
+{
+ System.out.println("Starting client stream socket test");
+
+ /* Simple connection and read test */
+ System.out.println("Test 1: Connection to daytime port on local host");
+ try
+ {
+ InetAddress addr = InetAddress.getByName("127.0.0.1");
+
+ Socket s = new Socket(addr, 13);
+
+ InputStream is = s.getInputStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+
+ for (String str = br.readLine(); ; str = br.readLine())
+ {
+ if (str == null)
+ break;
+ System.out.println(str);
+ }
+ s.close();
+ System.out.println("PASSED: daytime test");
+ }
+ catch(IOException e)
+ {
+ System.out.println("FAILED: daytime test: " + e);
+ }
+
+ /* Simple connection refused test */
+ System.out.println("Test 2: Connection refused test");
+ try
+ {
+ InetAddress addr = InetAddress.getByName("127.0.0.1");
+
+ Socket s = new Socket(addr, 47);
+ s.close();
+
+ System.out.print("WARNING: Cannot perform connection refused test");
+ System.out.println(" because someone is listening on localhost:47");
+ }
+ catch(IOException e)
+ {
+ System.out.println("PASSED: connection refused test: " + e.getMessage());
+ }
+
+ /* Socket attributes test */
+ System.out.println("Test 3: Connection attributes");
+ try
+ {
+ Socket s = new Socket("www.netscape.com", 80);
+
+ String laddr = s.getLocalAddress().getHostName();
+ int lport = s.getLocalPort();
+ String raddr = s.getInetAddress().getHostName();
+ int rport = s.getPort();
+
+ System.out.println("Local Address is: " + laddr);
+ System.out.println("Local Port is: " + lport);
+ System.out.println("Remote Address is: " + raddr);
+ System.out.println("Remote Port is: " + rport);
+ System.out.println("Socket.toString is: " + s);
+
+ if ( (laddr == null) ||
+ ((lport < 0) || (lport > 65535)) ||
+ (raddr.indexOf("netscape.com") == -1) ||
+ (rport != 80))
+ System.out.println("FAILED: connection attribute test");
+ else
+ System.out.println("PASSED: connection attribute test");
+
+ s.close();
+ }
+ catch(IOException e)
+ {
+ System.out.println("FAILED: connection attributes test: " + e.getMessage());
+ }
+
+ /* Socket options test */
+ System.out.println("Test 4: Socket options");
+ Socket s = new Socket("127.0.0.1", 23);
+
+ try
+ {
+ // SO_TIMEOUT
+ System.out.println("SO_TIMEOUT = " + s.getSoTimeout());
+ System.out.println("Setting SO_TIMEOUT to 142");
+ s.setSoTimeout(142);
+ System.out.println("SO_TIMEOUT = " + s.getSoTimeout());
+ System.out.println("Setting SO_TIMEOUT to 0");
+ s.setSoTimeout(0);
+ System.out.println("SO_TIMEOUT = " + s.getSoTimeout());
+ }
+ catch (IOException e)
+ {
+ System.out.println("WARNING: SO_TIMEOUT problem: " + e.getMessage());
+ System.out.println("This is ok on Linux");
+ }
+ try
+ {
+ // Try TCP_NODELAY
+ System.out.println("TCP_NODELAY = " + s.getTcpNoDelay());
+ System.out.println("Setting TCP_NODELAY to true");
+ s.setTcpNoDelay(true);
+ System.out.println("TCP_NODELAY = " + s.getTcpNoDelay());
+ System.out.println("Setting TCP_NODELAY to false");
+ s.setTcpNoDelay(false);
+ System.out.println("TCP_NODELAY = " + s.getTcpNoDelay());
+
+ // Try SO_LINGER
+ System.out.println("SO_LINGER = " + s.getSoLinger());
+ System.out.println("Setting SO_LINGER to 100");
+ s.setSoLinger(true, 100);
+ System.out.println("SO_LINGER = " + s.getSoLinger());
+ System.out.println("Setting SO_LINGER to off");
+ s.setSoLinger(false, 0);
+ System.out.println("SO_LINGER = " + s.getSoLinger());
+
+ System.out.println("PASSED: socket options test");
+ }
+ catch(IOException e)
+ {
+ System.out.println("FAILED: socket options test: " + e.getMessage());
+ }
+ s.close();
+
+ /* Simple read/write test */
+ System.out.println("Test 5: Simple read/write test");
+ try
+ {
+ System.out.println("Downloading the Transmeta homepage");
+ s = new Socket("www.transmeta.com", 80);
+
+ BufferedReader in = new BufferedReader(new
+ InputStreamReader(s.getInputStream()));
+ PrintWriter out = new PrintWriter(new
+ OutputStreamWriter(s.getOutputStream()));
+
+ out.print("GET /\r\n");
+ out.flush();
+
+ for (String str = in.readLine(); ; str = in.readLine())
+ {
+ if (str == null)
+ break;
+ System.out.println(str);
+ }
+
+ s.close();
+ System.out.println("PASSED: simple read/write test");
+ }
+ catch(IOException e)
+ {
+ System.out.println("FAILED: simple read/write test: " + e.getMessage());
+ }
+
+ /* Connect to our server socket */
+ System.out.println("Test 6: Connect to ServerSocket");
+ try
+ {
+ s = new Socket("localhost", 9999);
+
+ PrintWriter out = new PrintWriter(new
+ OutputStreamWriter(s.getOutputStream()));
+
+ out.println("Hello, there server socket");
+ out.print("I'm dun");
+ out.flush();
+ s.close();
+ System.out.println("PASSED: connect to server socket");
+ }
+ catch(Exception e)
+ {
+ System.out.println("FAILED: connect to server socket: " + e);
+ }
+
+ System.out.println("Client stream socket test complete");
+}
+
+}
+
diff --git a/test/java.net/Makefile.am b/test/java.net/Makefile.am
new file mode 100644
index 000000000..f57f67fbb
--- /dev/null
+++ b/test/java.net/Makefile.am
@@ -0,0 +1,9 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+JAVAROOT = .
+
+check_JAVA = ClientDatagram.java ClientSocket.java MulticastClient.java \
+ MulticastServer.java ServerDatagram.java ServerSocketTest.java \
+ SubSocket.java TestNameLookups.java URLTest.java
+
+EXTRA_DIST = BUGS runtest
diff --git a/test/java.net/MulticastClient.java b/test/java.net/MulticastClient.java
new file mode 100644
index 000000000..8dc18fe82
--- /dev/null
+++ b/test/java.net/MulticastClient.java
@@ -0,0 +1,65 @@
+/* Test Multicast Sockets */
+
+import java.net.*;
+import java.io.*;
+
+public class MulticastClient
+{
+
+public static void
+main(String[] argv) throws IOException
+{
+ System.out.println("Starting multicast tests");
+ System.out.println("NOTE: You need to do an 'ifconfig <interface> " +
+ "multicast' or this will fail on linux");
+
+ byte[] buf = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o','r','l','d' };
+
+ /* Simple Send */
+ System.out.println("Test 1: Multicast send/receive test");
+ try
+ {
+ InetAddress addr = InetAddress.getByName("234.0.0.1");
+
+ MulticastSocket s = new MulticastSocket();
+ DatagramPacket p = new DatagramPacket(buf, buf.length, addr, 3333);
+
+ s.joinGroup(addr);
+ s.send(p);
+ s.close();
+ }
+ catch(IOException e)
+ {
+ System.out.println("FAILED: simple multicast send: " + e);
+ }
+
+ /* Options */
+ System.out.println("Test 2: Multicast socket options");
+ try
+ {
+ InetAddress addr;
+ MulticastSocket s = new MulticastSocket();
+
+ System.out.println("TTL = " + s.getTTL());
+ System.out.println("Setting TTT to 121");
+ s.setTTL((byte)12);
+ System.out.println("TTL = " + s.getTTL());
+
+ InetAddress oaddr = s.getInterface();
+ System.out.println("Multicast Interface = " + oaddr);
+ System.out.println("Setting interface to localhost");
+ addr = InetAddress.getByName("198.211.138.177");
+ s.setInterface(addr);
+ System.out.println("Multicast Interface = " + s.getInterface());
+ System.out.println("Setting interface to " + oaddr);
+ s.setInterface(oaddr);
+ System.out.println("Multicast Interface = " + s.getInterface());
+ }
+ catch(IOException e)
+ {
+ System.out.println("FAILED: multicast options: " + e);
+ }
+}
+
+}
+
diff --git a/test/java.net/MulticastServer.java b/test/java.net/MulticastServer.java
new file mode 100644
index 000000000..1a54f99eb
--- /dev/null
+++ b/test/java.net/MulticastServer.java
@@ -0,0 +1,57 @@
+/* Mulitcast Server Socket for testing */
+
+import java.io.*;
+import java.net.*;
+
+public class MulticastServer
+{
+
+private MulticastSocket s;
+
+public static void
+main(String[] argv) throws IOException
+{
+ MulticastServer ms = new MulticastServer(3333);
+ ms.run();
+}
+
+public
+MulticastServer(int port) throws IOException
+{
+ s = new MulticastSocket(port);
+ System.out.println("Server multicast socket created");
+}
+
+public void
+run()
+{
+ try
+ {
+ byte[] buf = new byte[255];
+
+ DatagramPacket p = new DatagramPacket(buf, buf.length);
+ InetAddress addr = InetAddress.getByName("234.0.0.1");
+
+ p.setLength(buf.length);
+
+ System.out.println("Joining multicast group");
+ s.joinGroup(addr);
+ System.out.print("Receiving ...");
+ s.receive(p);
+ System.out.println("");
+ s.leaveGroup(addr);
+ System.out.println("ServerDatagram: received " + p.getLength() +
+ " bytes from " + p.getAddress().getHostName() + ":" +
+ p.getPort());
+ System.out.println("Data: " + new String(p.getData()));
+
+ System.out.println("PASSED multicast server test");
+ }
+ catch (IOException e)
+ {
+ System.out.println("FAILED: MulticastServer caught an exception: " + e);
+ }
+}
+
+}
+
diff --git a/test/java.net/ServerDatagram.java b/test/java.net/ServerDatagram.java
new file mode 100644
index 000000000..17ce44a27
--- /dev/null
+++ b/test/java.net/ServerDatagram.java
@@ -0,0 +1,52 @@
+/* Server Datagram Socket for testing */
+
+import java.io.*;
+import java.net.*;
+
+public class ServerDatagram implements Runnable
+{
+
+private DatagramSocket s;
+
+public static void
+main(String[] argv) throws IOException
+{
+ ServerDatagram sd = new ServerDatagram(37900);
+ sd.run();
+}
+
+public
+ServerDatagram(int port) throws SocketException
+{
+ s = new DatagramSocket(port);
+ System.out.println("Server datagram socket created");
+}
+
+public void
+run()
+{
+ try
+ {
+ byte[] buf = new byte[65535];
+
+ DatagramPacket p = new DatagramPacket(buf, buf.length);
+
+ p.setLength(buf.length);
+
+ s.receive(p);
+ System.out.println("ServerDatagram: received " + p.getLength() +
+ " bytes from " + p.getAddress().getHostName() + ":" +
+ p.getPort());
+
+ if (p.getLength() != 65332)
+ throw new IOException("Incorrect data size");
+ System.out.println("PASSED max values test");
+ }
+ catch (IOException e)
+ {
+ System.out.print("FAILED: ServerDatagram caught an exception: " + e);
+ }
+}
+
+}
+
diff --git a/test/java.net/ServerSocketTest.java b/test/java.net/ServerSocketTest.java
new file mode 100644
index 000000000..f444963a9
--- /dev/null
+++ b/test/java.net/ServerSocketTest.java
@@ -0,0 +1,53 @@
+/* Class to test server sockets */
+
+import java.io.*;
+import java.net.*;
+
+public class ServerSocketTest extends ServerSocket
+{
+
+public
+ServerSocketTest(int port) throws IOException
+{
+ super(port);
+}
+
+public static void
+main(String[] argv)
+{
+ System.out.println("Starting up server socket");
+
+ try {
+ ServerSocketTest ss = new ServerSocketTest(9999);
+
+ System.out.println("Created server socket bound to port " +
+ ss.getLocalPort() + " on local address " +
+ ss.getInetAddress());
+
+ SubSocket s = new SubSocket();
+ ss.implAccept(s);
+// Socket s = ss.accept();
+
+ System.out.println("Got a connection from " + s.getInetAddress() +
+ " on port " + s.getPort());
+
+ BufferedReader br = new BufferedReader(new
+ InputStreamReader(s.getInputStream()));
+
+ for (String str = br.readLine(); ; str = br.readLine())
+ {
+ if (str == null)
+ break;
+ System.out.println(str);
+ }
+ s.close();
+ ss.close();
+ System.out.println("PASSED: server socket test");
+ }
+ catch (Exception e) {
+ System.out.println("FAILED: server socket test: " + e);
+ }
+}
+
+}
+
diff --git a/test/java.net/SubSocket.java b/test/java.net/SubSocket.java
new file mode 100644
index 000000000..97da4471c
--- /dev/null
+++ b/test/java.net/SubSocket.java
@@ -0,0 +1,6 @@
+/* Quick and dirty Socket subclass */
+
+public class SubSocket extends java.net.Socket
+{
+}
+
diff --git a/test/java.net/TestNameLookups.java b/test/java.net/TestNameLookups.java
new file mode 100644
index 000000000..592d9e01f
--- /dev/null
+++ b/test/java.net/TestNameLookups.java
@@ -0,0 +1,103 @@
+/* A class to test my java.net.InetAddress implementation */
+
+import java.net.*;
+
+public class TestNameLookups extends Object
+{
+public static void
+main(String[] argv) throws UnknownHostException
+{
+ InetAddress addr;
+
+ System.out.println("Started address lookup test");
+
+ /* Test local host */
+ try
+ {
+ addr = InetAddress.getLocalHost();
+
+ System.out.println("The local hostname is " + addr.getHostName() +
+ " with an IP address of " + addr.getHostAddress());
+ }
+ catch(UnknownHostException e)
+ {
+ System.out.println("WARNING: Can't resolve local hostname");
+ }
+
+ /* Test simple lookup by IP */
+ addr = InetAddress.getByName("18.159.0.42");
+
+ System.out.println("Looked up IP addres 18.159.0.42 and got back a " +
+ "hostname of " + addr.getHostName());
+
+ /* Test failed reverse lookup of IP */
+ addr = InetAddress.getByName("194.72.246.154");
+
+ System.out.println("Looked up IP addres 194.72.246.154 and got back a " +
+ "hostname of " + addr.getHostName());
+
+ /* Test mangled/invalid IP's */
+ try { addr = InetAddress.getByName("122.24.1."); }
+ catch (UnknownHostException e) {
+ System.out.println("Passed bad IP test 1");
+ }
+
+ try { addr = InetAddress.getByName("122.24.52"); }
+ catch (UnknownHostException e) {
+ System.out.println("Passed bad IP test 2");
+ }
+
+ try { addr = InetAddress.getByName("122.256.52.1"); }
+ catch (UnknownHostException e) {
+ System.out.println("Passed bad IP test 3");
+ }
+
+ /* Test simple lookup by name with external info */
+ addr = InetAddress.getByName("www.starnews.com");
+ System.out.println("Looked up host www.starnews.com and got back an " +
+ "IP address of " + addr.getHostAddress());
+ byte[] octets = addr.getAddress();
+ System.out.println("Raw Address Bytes: octet1=" + (int)octets[0] +
+ " octets2=" + (int)octets[1] + " octet3=" + (int)octets[2] +
+ " octets4=" + (int)octets[3]);
+ System.out.println("toString() returned: " + addr.toString());
+ System.out.println("isMulticastAddress returned: "
+ + addr.isMulticastAddress());
+
+ /* Test complex lookup */
+ System.out.println("Looking up all addresses for indiana.edu ...");
+ InetAddress[] list = InetAddress.getAllByName("indiana.edu");
+ for (int i = 0; i < list.length; i++)
+ {
+ addr = list[i];
+
+ System.out.println(" Hostname: " + addr.getHostName() +
+ " IP Address: " + addr.getHostAddress());
+ }
+
+ /* Test equality */
+ InetAddress addr1 = InetAddress.getByName("www.urbanophile.com");
+ InetAddress addr2 = InetAddress.getByName("www.urbanophile.com");
+
+ if (addr1.equals(addr2) && addr2.equals(addr1))
+ System.out.println("Passed equality test #1");
+ else
+ System.out.println("Failed equality test #1");
+
+ addr1 = InetAddress.getByName("www.ac.com");
+ addr2 = InetAddress.getByName("www.hungry.com");
+
+ if (!addr1.equals(addr2) && !addr2.equals(addr1))
+ System.out.println("Passed equality test #2");
+ else
+ System.out.println("Failed equality test #2");
+
+ /* Quick test to see if it looks like we're caching things */
+ addr1 = InetAddress.getByName("www.urbanophile.com");
+ System.out.println("Got " + addr1.getHostName() + " " + addr1.getHostAddress());
+ addr2 = InetAddress.getByName("www.hungry.com");
+ System.out.println("Got " + addr2.getHostName() + " " + addr2.getHostAddress());
+}
+
+}
+
diff --git a/test/java.net/URLTest.java b/test/java.net/URLTest.java
new file mode 100644
index 000000000..82d0929f4
--- /dev/null
+++ b/test/java.net/URLTest.java
@@ -0,0 +1,150 @@
+/* Test URL's */
+
+import java.net.*;
+import java.io.*;
+
+public class URLTest
+{
+
+public static void
+main(String argv[])
+{
+ System.out.println("Starting URL tests");
+
+ /* Simple URL test */
+
+ System.out.println("Test 1: Simple URL test");
+
+ try
+ {
+ URL url = new URL("http", "www.fsf.org", 80, "/");
+
+ if (!url.getProtocol().equals("http") ||
+ !url.getHost().equals("www.fsf.org") ||
+ url.getPort() != 80 ||
+ !url.getFile().equals("/"))
+ System.out.println("FAILED: Simple URL test");
+
+ System.out.println("URL is: " + url.toString());
+
+ URLConnection uc = url.openConnection();
+
+ if (uc instanceof HttpURLConnection)
+ System.out.println("Got the expected connection type");
+
+ HttpURLConnection hc = (HttpURLConnection)uc;
+
+ hc.connect();
+
+ System.out.println("Dumping response headers");
+ for (int i = 0; ; i++)
+ {
+ String key = hc.getHeaderFieldKey(i);
+ if (key == null)
+ break;
+
+ System.out.println(key + ": " + hc.getHeaderField(i));
+ }
+
+ System.out.println("Dumping contents");
+ BufferedReader br = new BufferedReader(new
+ InputStreamReader(hc.getInputStream()));
+
+ for (String str = br.readLine(); str != null; str = br.readLine())
+ System.out.println(str);
+
+ hc.disconnect();
+
+ System.out.println("Content Type: " + hc.getContentType());
+ System.out.println("Content Encoding: " + hc.getContentEncoding());
+ System.out.println("Content Length: " + hc.getContentLength());
+ System.out.println("Date: " + hc.getDate());
+ System.out.println("Expiration: " + hc.getExpiration());
+ System.out.println("Last Modified: " + hc.getLastModified());
+
+ System.out.println("PASSED: Simple URL test");
+ }
+ catch(IOException e)
+ {
+ System.out.println("FAILED: Simple URL test: " + e);
+ }
+
+ // Parsing test
+ System.out.println("Test 2: URL parsing test");
+ try
+ {
+ URL url = new URL("http://www.urbanophile.com/arenn/trans/trans.html#mis");
+ if (!url.toString().equals(
+ "http://www.urbanophile.com/arenn/trans/trans.html#mis"))
+ System.out.println("FAILED: Parse URL test: " + url.toString());
+ else {
+ System.out.println("Parsed ok: " + url.toString());
+ url = new URL("http://www.foo.com:8080/#");
+ if (!url.toString().equals("http://www.foo.com:8080/#"))
+ System.out.println("FAILED: Parse URL test: " + url.toString());
+ else {
+ System.out.println("Parsed ok: " + url.toString());
+ url = new URL("http://www.bar.com/test:file/");
+ if (!url.toString().equals("http://www.bar.com/test:file/"))
+ System.out.println("FAILED: Parse URL test: " + url.toString());
+ else {
+ System.out.println("Parsed ok: " + url.toString());
+ url = new URL("http://www.gnu.org");
+ if (!url.toString().equals("http://www.gnu.org/"))
+ System.out.println("FAILED: Parse URL test: " + url.toString());
+ else {
+ System.out.println("Parsed ok: " + url.toString());
+ url = new URL("HTTP://www.fsf.org/");
+ if (!url.toString().equals("http://www.fsf.org/"))
+ System.out.println("FAILED: Parse URL test: " + url.toString());
+ else {
+ System.out.println("Parsed ok: " + url.toString());
+ System.out.println("PASSED: URL parse test");
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ System.out.println("FAILED: URL parsing test: " + e);
+ }
+
+ // getContent test
+ System.out.println("Test 3: getContent test");
+ try
+ {
+ URL url = new URL("http://localhost/~arenn/services.txt");
+
+ Object obj = url.getContent();
+ System.out.println("Object type is: " + obj.getClass().getName());
+
+ if (obj instanceof InputStream)
+ {
+ System.out.println("Got InputStream, so dumping contents");
+ BufferedReader br = new BufferedReader(new
+ InputStreamReader((InputStream)obj));
+
+ for (String str = br.readLine(); str != null; str = br.readLine())
+ System.out.println(str);
+
+ br.close();
+ }
+ else
+ {
+ System.out.println("FAILED: Object is not an InputStream");
+ }
+
+ System.out.println("PASSED: getContent test");
+ }
+ catch (IOException e)
+ {
+ System.out.println("FAILED: getContent test: " + e);
+ }
+
+ System.out.println("URL test complete");
+}
+
+}
+
diff --git a/test/java.net/runtest b/test/java.net/runtest
new file mode 100755
index 000000000..4439aa099
--- /dev/null
+++ b/test/java.net/runtest
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+echo "Running java.net tests"
+echo "I assume japhar is in /usr/local/japhar"
+echo "Please make sure background processes don't block on a tty write"
+echo "Please do an 'ifconfig multicast' and 'ifconfig allmulti' on your"
+echo "network interfaces"
+
+export CLASSPATH=.:/usr/local/japhar/share
+export PATH=$PATH:/usr/local/japhar/bin
+
+echo "Executing name lookup test ..."
+japhar TestNameLookups
+
+echo "Executing stream socket tests ..."
+japhar ServerSocketTest &
+japhar ClientSocket
+
+echo "Executing datagram socket tests ..."
+japhar ServerDatagram &
+japhar ClientDatagram
+
+echo "Executing multicast socket tests ..."
+japhar MulticastServer &
+japhar MulticastClient
+
+echo "Executing URL tests ..."
+japhar URLTest
+
+echo "java.net Testing complete."
+exit 0
+