aboutsummaryrefslogtreecommitdiff
path: root/libjava/gnu/java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/gnu/java')
-rw-r--r--libjava/gnu/java/net/PlainDatagramSocketImpl.java280
-rw-r--r--libjava/gnu/java/net/PlainSocketImpl.java401
-rw-r--r--libjava/gnu/java/net/SocketInputStream.java204
-rw-r--r--libjava/gnu/java/net/SocketOutputStream.java166
-rw-r--r--libjava/gnu/java/net/natPlainDatagramSocketImplNoNet.cc119
-rw-r--r--libjava/gnu/java/net/natPlainDatagramSocketImplPosix.cc750
-rw-r--r--libjava/gnu/java/net/natPlainDatagramSocketImplWin32.cc704
-rw-r--r--libjava/gnu/java/net/natPlainSocketImplNoNet.cc128
-rw-r--r--libjava/gnu/java/net/natPlainSocketImplPosix.cc857
-rw-r--r--libjava/gnu/java/net/natPlainSocketImplWin32.cc784
10 files changed, 4393 insertions, 0 deletions
diff --git a/libjava/gnu/java/net/PlainDatagramSocketImpl.java b/libjava/gnu/java/net/PlainDatagramSocketImpl.java
new file mode 100644
index 0000000..a0785db
--- /dev/null
+++ b/libjava/gnu/java/net/PlainDatagramSocketImpl.java
@@ -0,0 +1,280 @@
+/* PlainDatagramSocketImpl.java -- Default DatagramSocket implementation
+ Copyright (C) 1998, 1999, 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocketImpl;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.SocketAddress;
+import java.net.SocketOptions;
+import java.net.SocketException;
+import gnu.classpath.Configuration;
+
+/**
+ * Written using on-line Java Platform 1.2 API Specification, as well
+ * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * 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.
+ *
+ * @author Aaron M. Renn <arenn@urbanophile.com>
+ * @author Warren Levy <warrenl@cygnus.com>
+ */
+public final class PlainDatagramSocketImpl extends DatagramSocketImpl
+{
+ // Static initializer to load native library
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary("javanet");
+ }
+ }
+
+ // These fields are mirrored for use in native code to avoid cpp conflicts
+ // when the #defines in system header files are the same as the public fields.
+ static final int _Jv_TCP_NODELAY_ = SocketOptions.TCP_NODELAY,
+ _Jv_SO_BINDADDR_ = SocketOptions.SO_BINDADDR,
+ _Jv_SO_REUSEADDR_ = SocketOptions.SO_REUSEADDR,
+ _Jv_SO_BROADCAST_ = SocketOptions.SO_BROADCAST,
+ _Jv_SO_OOBINLINE_ = SocketOptions.SO_OOBINLINE,
+ _Jv_IP_MULTICAST_IF_ = SocketOptions.IP_MULTICAST_IF,
+ _Jv_IP_MULTICAST_IF2_ = SocketOptions.IP_MULTICAST_IF2,
+ _Jv_IP_MULTICAST_LOOP_ = SocketOptions.IP_MULTICAST_LOOP,
+ _Jv_IP_TOS_ = SocketOptions.IP_TOS,
+ _Jv_SO_LINGER_ = SocketOptions.SO_LINGER,
+ _Jv_SO_TIMEOUT_ = SocketOptions.SO_TIMEOUT,
+ _Jv_SO_SNDBUF_ = SocketOptions.SO_SNDBUF,
+ _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF,
+ _Jv_SO_KEEPALIVE_ = SocketOptions.SO_KEEPALIVE;
+
+ /**
+ * This is the actual underlying file descriptor
+ */
+ int fnum = -1;
+
+ // FIXME: Is this necessary? Could it help w/ DatagramSocket.getLocalAddress?
+ // InetAddress address;
+
+ // localAddress cache
+ InetAddress localAddress;
+
+ // 'timeout' is set/read by setOption/getOption.
+ int timeout = 0;
+
+ /**
+ * Default do nothing constructor
+ */
+ public PlainDatagramSocketImpl()
+ {
+ }
+
+ /**
+ * 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 void bind(int lport, InetAddress laddr)
+ throws SocketException;
+
+ protected native void connect (InetAddress i, int port)
+ throws SocketException;
+
+ protected native void disconnect ();
+
+ /**
+ * Creates a new datagram socket
+ *
+ * @exception SocketException If an error occurs
+ */
+ protected native void create() throws SocketException;
+
+ protected native int peek(InetAddress i) throws IOException;
+
+ protected native int peekData (DatagramPacket dp) throws IOException;
+
+ /**
+ * Sets the Time to Live value for the socket
+ *
+ * @param ttl The new TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native void setTimeToLive(int ttl) throws IOException;
+
+ /**
+ * Gets the Time to Live value for the socket
+ *
+ * @return The TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native int getTimeToLive() throws IOException;
+
+ /**
+ * Sends a packet of data to a remote host
+ *
+ * @param packet The packet to send
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native void send(DatagramPacket p) throws IOException;
+
+ /**
+ * 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 void receive(DatagramPacket p) throws IOException;
+
+ /**
+ * 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 void setOption(int optID, Object value) throws SocketException;
+
+ /**
+ * 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 Object getOption(int optID) throws SocketException;
+
+ private native void mcastGrp(InetAddress inetaddr, NetworkInterface netIf,
+ boolean join) throws IOException;
+
+ /**
+ * Closes the socket
+ */
+ protected native void close();
+
+ /**
+ * Gets the Time to Live value for the socket
+ *
+ * @return The TTL value
+ *
+ * @exception IOException If an error occurs
+ *
+ * @deprecated 1.2
+ */
+ protected byte getTTL() throws IOException
+ {
+ return (byte) getTimeToLive();
+ }
+
+ /**
+ * Sets the Time to Live value for the socket
+ *
+ * @param ttl The new TTL value
+ *
+ * @exception IOException If an error occurs
+ *
+ * @deprecated 1.2
+ */
+ protected void setTTL(byte ttl) throws IOException
+ {
+ setTimeToLive(((int) ttl) & 0xFF);
+ }
+
+ /**
+ * Joins a multicast group
+ *
+ * @param addr The group to join
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void join(InetAddress inetaddr) throws IOException
+ {
+ mcastGrp(inetaddr, null, true);
+ }
+
+ /**
+ * Leaves a multicast group
+ *
+ * @param addr The group to leave
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void leave(InetAddress inetaddr) throws IOException
+ {
+ mcastGrp(inetaddr, null, false);
+ }
+
+ protected void joinGroup (SocketAddress mcastaddr, NetworkInterface netIf)
+ throws IOException
+ {
+ mcastGrp(((InetSocketAddress)mcastaddr).getAddress(), netIf, true);
+ }
+
+ protected void leaveGroup (SocketAddress mcastaddr, NetworkInterface netIf)
+ throws IOException
+ {
+ mcastGrp(((InetSocketAddress)mcastaddr).getAddress(), netIf, false);
+ }
+
+ protected void finalize() throws Throwable
+ {
+ synchronized (this)
+ {
+ if (fnum != -1)
+ close();
+ }
+ super.finalize();
+ }
+}
diff --git a/libjava/gnu/java/net/PlainSocketImpl.java b/libjava/gnu/java/net/PlainSocketImpl.java
new file mode 100644
index 0000000..182f357f
--- /dev/null
+++ b/libjava/gnu/java/net/PlainSocketImpl.java
@@ -0,0 +1,401 @@
+/* PlainSocketImpl.java -- Default socket implementation
+ Copyright (C) 1998, 1999, 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketImpl;
+import java.net.SocketOptions;
+import gnu.classpath.Configuration;
+
+/**
+ * Written using on-line Java Platform 1.2 API Specification, as well
+ * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * 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
+ *
+ * @author Per Bothner <bothner@cygnus.com>
+ * @author Nic Ferrier <nferrier@tapsellferrier.co.uk>
+ * @author Aaron M. Renn <arenn@urbanophile.com>
+ */
+public final class PlainSocketImpl extends SocketImpl
+{
+ // Static initializer to load native library.
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary("javanet");
+ }
+ }
+
+ // These fields are mirrored for use in native code to avoid cpp conflicts
+ // when the #defines in system header files are the same as the public fields.
+ static final int _Jv_TCP_NODELAY_ = SocketOptions.TCP_NODELAY,
+ _Jv_SO_BINDADDR_ = SocketOptions.SO_BINDADDR,
+ _Jv_SO_REUSEADDR_ = SocketOptions.SO_REUSEADDR,
+ _Jv_SO_BROADCAST_ = SocketOptions.SO_BROADCAST,
+ _Jv_SO_OOBINLINE_ = SocketOptions.SO_OOBINLINE,
+ _Jv_IP_MULTICAST_IF_ = SocketOptions.IP_MULTICAST_IF,
+ _Jv_IP_MULTICAST_IF2_ = SocketOptions.IP_MULTICAST_IF2,
+ _Jv_IP_MULTICAST_LOOP_ = SocketOptions.IP_MULTICAST_LOOP,
+ _Jv_IP_TOS_ = SocketOptions.IP_TOS,
+ _Jv_SO_LINGER_ = SocketOptions.SO_LINGER,
+ _Jv_SO_TIMEOUT_ = SocketOptions.SO_TIMEOUT,
+ _Jv_SO_SNDBUF_ = SocketOptions.SO_SNDBUF,
+ _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF,
+ _Jv_SO_KEEPALIVE_ = SocketOptions.SO_KEEPALIVE;
+
+ /**
+ * The OS file handle representing the socket.
+ * This is used for reads and writes to/from the socket and
+ * to close it.
+ *
+ * When the socket is closed this is reset to -1.
+ */
+ int fnum = -1;
+
+ // This value is set/read by setOption/getOption.
+ int timeout = 0;
+
+ // localAddress cache
+ InetAddress localAddress;
+
+ /**
+ * A cached copy of the in stream for reading from the socket.
+ */
+ private InputStream in;
+
+ /**
+ * A cached copy of the out stream for writing to the socket.
+ */
+ private OutputStream out;
+
+ /**
+ * Default do nothing constructor
+ */
+ public PlainSocketImpl()
+ {
+ }
+
+ protected void finalize() throws Throwable
+ {
+ synchronized (this)
+ {
+ if (fnum != -1)
+ try
+ {
+ close();
+ }
+ catch (IOException ex)
+ {
+ // ignore
+ }
+ }
+ super.finalize();
+ }
+
+ /**
+ * 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 void setOption(int optID, Object value) 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 Object getOption(int optID) throws SocketException;
+
+ public native void shutdownInput () throws IOException;
+
+ public native void shutdownOutput () 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 native void create (boolean stream) 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 void connect (String host, int port) throws IOException
+ {
+ connect (new InetSocketAddress (InetAddress.getByName(host), port), 0);
+ }
+
+ /**
+ * 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 void connect (InetAddress host, int port) throws IOException
+ {
+ connect (new InetSocketAddress (host, port), 0);
+ }
+
+ protected native void connect (SocketAddress addr, int timeout)
+ 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 native void bind (InetAddress host, int port) 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 void listen (int backlog) throws IOException;
+
+ private native void accept (PlainSocketImpl s) throws IOException;
+
+ /**
+ * 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 void accept (SocketImpl s) throws IOException
+ {
+ accept((PlainSocketImpl) s);
+ }
+
+ /**
+ * 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 native int available() 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 void close () throws IOException;
+
+ protected native void sendUrgentData(int data)
+ throws IOException;
+
+ native int read() 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
+ */
+ native int read(byte[] buffer, int offset, int count)
+ throws IOException;
+
+ native void write(int c) 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
+ */
+ native void write(byte[] buffer, int offset, int count)
+ throws IOException;
+
+ /**
+ * Returns an InputStream object for reading from this socket. This will
+ * be an instance of SocketInputStream.
+ *
+ * @return An input stream attached to the socket.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized InputStream getInputStream() throws IOException
+ {
+ if (in == null)
+ in = new SocketInputStream();
+
+ return in;
+ }
+
+ /**
+ * Returns an OutputStream object for writing to this socket. This will
+ * be an instance of SocketOutputStream.
+ *
+ * @return An output stream attached to the socket.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized OutputStream getOutputStream() throws IOException
+ {
+ if (out == null)
+ out = new SocketOutputStream();
+
+ return out;
+ }
+
+ /**
+ * A stream which reads from the socket implementation.
+ *
+ * @author Nic Ferrier <nferrier@tapsellferrier.co.uk>
+ */
+ class SocketInputStream
+ extends InputStream
+ {
+ SocketInputStream()
+ {
+ }
+
+ public final void close() throws IOException
+ {
+ PlainSocketImpl.this.close();
+ }
+
+ public final int available() throws IOException
+ {
+ return PlainSocketImpl.this.available();
+ }
+
+ public final int read() throws IOException
+ {
+ return PlainSocketImpl.this.read();
+ }
+
+ public final int read(byte[] buffer, int offset, int length)
+ throws IOException
+ {
+ return PlainSocketImpl.this.read(buffer, offset, length);
+ }
+
+ public final int read(byte[] buffer)
+ throws IOException
+ {
+ return PlainSocketImpl.this.read(buffer, 0, buffer.length);
+ }
+ }
+
+ /** A stream which writes to the socket implementation.
+ *
+ * @author Nic Ferrier <nferrier@tapsellferrier.co.uk>
+ */
+ class SocketOutputStream
+ extends OutputStream
+ {
+ public final void close() throws IOException
+ {
+ PlainSocketImpl.this.close();
+ }
+
+ public final void write(int c) throws IOException
+ {
+ PlainSocketImpl.this.write(c);
+ }
+
+ public final void write(byte[] buffer, int offset, int length)
+ throws IOException
+ {
+ PlainSocketImpl.this.write(buffer, offset, length);
+ }
+
+ public final void write(byte[] buffer)
+ throws IOException
+ {
+ PlainSocketImpl.this.write(buffer, 0, buffer.length);
+ }
+ }
+}
diff --git a/libjava/gnu/java/net/SocketInputStream.java b/libjava/gnu/java/net/SocketInputStream.java
new file mode 100644
index 0000000..90d703b
--- /dev/null
+++ b/libjava/gnu/java/net/SocketInputStream.java
@@ -0,0 +1,204 @@
+/* SocketInputStream.java -- An InputStream for Sockets
+ Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This class contains an implementation of <code>InputStream</code> for
+ * sockets. It in an internal only class used by <code>PlainSocketImpl</code>.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+class SocketInputStream extends InputStream
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The PlainSocketImpl object this stream is associated with
+ */
+private 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(buf[0] & 0xFF);
+ 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
+{
+ return(read(buf, 0, buf.length));
+}
+
+/*************************************************************************/
+
+/**
+ * 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
+{
+ int bytes_read = impl.read(buf, offset, len);
+ if (bytes_read == 0)
+ return(-1);
+
+ return(bytes_read);
+}
+
+} // class SocketInputStream
+
diff --git a/libjava/gnu/java/net/SocketOutputStream.java b/libjava/gnu/java/net/SocketOutputStream.java
new file mode 100644
index 0000000..4d68e3c
--- /dev/null
+++ b/libjava/gnu/java/net/SocketOutputStream.java
@@ -0,0 +1,166 @@
+/* SocketOutputStream.java -- OutputStream for PlainSocketImpl
+ Copyright (C) 1998,2000 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This class is used internally by <code>PlainSocketImpl</code> to be the
+ * <code>OutputStream</code> subclass returned by its
+ * <code>getOutputStream method</code>. It expects only to be used in that
+ * context.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+class SocketOutputStream extends OutputStream
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The PlainSocketImpl object this stream is associated with
+ */
+private 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/libjava/gnu/java/net/natPlainDatagramSocketImplNoNet.cc b/libjava/gnu/java/net/natPlainDatagramSocketImplNoNet.cc
new file mode 100644
index 0000000..7cb5a2e
--- /dev/null
+++ b/libjava/gnu/java/net/natPlainDatagramSocketImplNoNet.cc
@@ -0,0 +1,119 @@
+/* Copyright (C) 2003 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+#include <platform.h>
+
+#include <gnu/java/net/PlainDatagramSocketImpl.h>
+#include <java/io/IOException.h>
+#include <java/lang/Object.h>
+#include <java/net/BindException.h>
+#include <java/net/DatagramPacket.h>
+#include <java/net/InetAddress.h>
+#include <java/net/NetworkInterface.h>
+#include <java/net/SocketException.h>
+
+void
+gnu::java::net::PlainDatagramSocketImpl::create ()
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("DatagramSocketImpl.create: unimplemented"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::bind (jint, ::java::net::InetAddress *)
+{
+ throw new ::java::net::BindException (
+ JvNewStringLatin1 ("DatagramSocketImpl.bind: unimplemented"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::connect (::java::net::InetAddress *, jint)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("DatagramSocketImpl.connect: unimplemented"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::disconnect ()
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("DatagramSocketImpl.disconnect: unimplemented"));
+}
+
+jint
+gnu::java::net::PlainDatagramSocketImpl::peek (::java::net::InetAddress *)
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("DatagramSocketImpl.peek: unimplemented"));
+}
+
+jint
+gnu::java::net::PlainDatagramSocketImpl::peekData (::java::net::DatagramPacket *)
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("DatagramSocketImpl.peekData: unimplemented"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::close ()
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("DatagramSocketImpl.close: unimplemented"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::send (::java::net::DatagramPacket *)
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("DatagramSocketImpl.send: unimplemented"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::receive (::java::net::DatagramPacket *)
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("DatagramSocketImpl.receive: unimplemented"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::setTimeToLive (jint)
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("DatagramSocketImpl.setTimeToLive: unimplemented"));
+}
+
+jint
+gnu::java::net::PlainDatagramSocketImpl::getTimeToLive ()
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("DatagramSocketImpl.getTimeToLive: unimplemented"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::mcastGrp (::java::net::InetAddress *,
+ ::java::net::NetworkInterface *,
+ jboolean)
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("DatagramSocketImpl.mcastGrp: unimplemented"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::setOption (jint, ::java::lang::Object *)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("DatagramSocketImpl.setOption: unimplemented"));
+}
+
+::java::lang::Object *
+gnu::java::net::PlainDatagramSocketImpl::getOption (jint)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("DatagramSocketImpl.getOption: unimplemented"));
+}
diff --git a/libjava/gnu/java/net/natPlainDatagramSocketImplPosix.cc b/libjava/gnu/java/net/natPlainDatagramSocketImplPosix.cc
new file mode 100644
index 0000000..f1897b7
--- /dev/null
+++ b/libjava/gnu/java/net/natPlainDatagramSocketImplPosix.cc
@@ -0,0 +1,750 @@
+/* Copyright (C) 2003 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+#include <platform.h>
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <errno.h>
+#include <string.h>
+
+#if HAVE_BSTRING_H
+// Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2
+#include <bstring.h>
+#endif
+
+#include <gcj/cni.h>
+#include <gnu/java/net/PlainDatagramSocketImpl.h>
+#include <java/io/IOException.h>
+#include <java/io/InterruptedIOException.h>
+#include <java/net/BindException.h>
+#include <java/net/SocketException.h>
+#include <java/net/InetAddress.h>
+#include <java/net/NetworkInterface.h>
+#include <java/net/DatagramPacket.h>
+#include <java/net/PortUnreachableException.h>
+#include <java/lang/InternalError.h>
+#include <java/lang/Object.h>
+#include <java/lang/Boolean.h>
+#include <java/lang/Integer.h>
+
+union SockAddr
+{
+ struct sockaddr_in address;
+#ifdef HAVE_INET6
+ struct sockaddr_in6 address6;
+#endif
+};
+
+union McastReq
+{
+#if HAVE_STRUCT_IP_MREQ
+ struct ip_mreq mreq;
+#endif
+#if HAVE_STRUCT_IPV6_MREQ
+ struct ipv6_mreq mreq6;
+#endif
+};
+
+union InAddr
+{
+ struct in_addr addr;
+#ifdef HAVE_INET6
+ struct in6_addr addr6;
+#endif
+};
+
+
+// FIXME: routines here and/or in natPlainSocketImpl.cc could throw
+// NoRouteToHostException; also consider UnknownHostException, ConnectException.
+
+void
+gnu::java::net::PlainDatagramSocketImpl::create ()
+{
+ int sock = _Jv_socket (AF_INET, SOCK_DGRAM, 0);
+
+ if (sock < 0)
+ {
+ char* strerr = strerror (errno);
+ throw new ::java::net::SocketException (JvNewStringUTF (strerr));
+ }
+
+ _Jv_platform_close_on_exec (sock);
+
+ // We use fnum in place of fd here. From leaving fd null we avoid
+ // the double close problem in FileDescriptor.finalize.
+ fnum = sock;
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::bind (jint lport,
+ ::java::net::InetAddress *host)
+{
+ union SockAddr u;
+ struct sockaddr *ptr = (struct sockaddr *) &u.address;
+ // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4.
+ jbyteArray haddress = host->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+
+ if (host != NULL)
+ memcpy (&u.address.sin_addr, bytes, len);
+ else
+ u.address.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ len = sizeof (struct sockaddr_in);
+ u.address.sin_port = htons (lport);
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ u.address6.sin6_family = AF_INET6;
+ memcpy (&u.address6.sin6_addr, bytes, len);
+ len = sizeof (struct sockaddr_in6);
+ u.address6.sin6_port = htons (lport);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (_Jv_bind (fnum, ptr, len) == 0)
+ {
+ socklen_t addrlen = sizeof(u);
+
+ if (lport != 0)
+ localPort = lport;
+ else if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0)
+ localPort = ntohs (u.address.sin_port);
+ else
+ goto error;
+
+ /* Allow broadcast by default. */
+ int broadcast = 1;
+ if (::setsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &broadcast,
+ sizeof (broadcast)) != 0)
+ goto error;
+
+ return;
+ }
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::BindException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::connect (::java::net::InetAddress *, jint)
+{
+ throw new ::java::lang::InternalError (JvNewStringLatin1 (
+ "PlainDatagramSocketImpl::connect: not implemented yet"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::disconnect ()
+{
+ throw new ::java::lang::InternalError (JvNewStringLatin1 (
+ "PlainDatagramSocketImpl::disconnect: not implemented yet"));
+}
+
+jint
+gnu::java::net::PlainDatagramSocketImpl::peek (::java::net::InetAddress *i)
+{
+ // FIXME: Deal with Multicast and if the socket is connected.
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ ssize_t retlen =
+ ::recvfrom (fnum, (char *) NULL, 0, MSG_PEEK, (sockaddr*) &u,
+ &addrlen);
+ if (retlen < 0)
+ goto error;
+ // FIXME: Deal with Multicast addressing and if the socket is connected.
+ jbyteArray raddr;
+ jint rport;
+ if (u.address.sin_family == AF_INET)
+ {
+ raddr = JvNewByteArray (4);
+ memcpy (elements (raddr), &u.address.sin_addr, 4);
+ rport = ntohs (u.address.sin_port);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ raddr = JvNewByteArray (16);
+ memcpy (elements (raddr), &u.address6.sin6_addr, 16);
+ rport = ntohs (u.address6.sin6_port);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
+
+ i->addr = raddr;
+ return rport;
+ error:
+ char* strerr = strerror (errno);
+
+ if (errno == ECONNREFUSED)
+ throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
+
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+}
+
+jint
+gnu::java::net::PlainDatagramSocketImpl::peekData (::java::net::DatagramPacket *p)
+{
+ // FIXME: Deal with Multicast and if the socket is connected.
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ jbyte *dbytes = elements (p->getData());
+ ssize_t retlen = 0;
+
+ // Do timeouts via select since SO_RCVTIMEO is not always available.
+ if (timeout > 0 && fnum >= 0 && fnum < FD_SETSIZE)
+ {
+ fd_set rset;
+ struct timeval tv;
+ FD_ZERO(&rset);
+ FD_SET(fnum, &rset);
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ int retval;
+ if ((retval = _Jv_select (fnum + 1, &rset, NULL, NULL, &tv)) < 0)
+ goto error;
+ else if (retval == 0)
+ throw new ::java::io::InterruptedIOException ();
+ }
+
+ retlen =
+ ::recvfrom (fnum, (char *) dbytes, p->getLength(), MSG_PEEK, (sockaddr*) &u,
+ &addrlen);
+ if (retlen < 0)
+ goto error;
+ // FIXME: Deal with Multicast addressing and if the socket is connected.
+ jbyteArray raddr;
+ jint rport;
+ if (u.address.sin_family == AF_INET)
+ {
+ raddr = JvNewByteArray (4);
+ memcpy (elements (raddr), &u.address.sin_addr, 4);
+ rport = ntohs (u.address.sin_port);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ raddr = JvNewByteArray (16);
+ memcpy (elements (raddr), &u.address6.sin6_addr, 16);
+ rport = ntohs (u.address6.sin6_port);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
+
+ p->setAddress (new ::java::net::InetAddress (raddr, NULL));
+ p->setPort (rport);
+ p->setLength ((jint) retlen);
+ return rport;
+
+ error:
+ char* strerr = strerror (errno);
+
+ if (errno == ECONNREFUSED)
+ throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
+
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+}
+
+// Close(shutdown) the socket.
+void
+gnu::java::net::PlainDatagramSocketImpl::close ()
+{
+ // Avoid races from asynchronous finalization.
+ JvSynchronize sync (this);
+
+ // The method isn't declared to throw anything, so we disregard
+ // the return value.
+ _Jv_close (fnum);
+ fnum = -1;
+ timeout = 0;
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::send (::java::net::DatagramPacket *p)
+{
+ // FIXME: Deal with Multicast and if the socket is connected.
+ jint rport = p->getPort();
+ union SockAddr u;
+ jbyteArray haddress = p->getAddress()->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+ struct sockaddr *ptr = (struct sockaddr *) &u.address;
+ jbyte *dbytes = elements (p->getData());
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+ memcpy (&u.address.sin_addr, bytes, len);
+ len = sizeof (struct sockaddr_in);
+ u.address.sin_port = htons (rport);
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ u.address6.sin6_family = AF_INET6;
+ memcpy (&u.address6.sin6_addr, bytes, len);
+ len = sizeof (struct sockaddr_in6);
+ u.address6.sin6_port = htons (rport);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (::sendto (fnum, (char *) dbytes, p->getLength(), 0, ptr, len) >= 0)
+ return;
+
+ char* strerr = strerror (errno);
+
+ if (errno == ECONNREFUSED)
+ throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
+
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::receive (::java::net::DatagramPacket *p)
+{
+ // FIXME: Deal with Multicast and if the socket is connected.
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ jbyte *dbytes = elements (p->getData());
+ ssize_t retlen = 0;
+
+ // Do timeouts via select since SO_RCVTIMEO is not always available.
+ if (timeout > 0 && fnum >= 0 && fnum < FD_SETSIZE)
+ {
+ fd_set rset;
+ struct timeval tv;
+ FD_ZERO(&rset);
+ FD_SET(fnum, &rset);
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ int retval;
+ if ((retval = _Jv_select (fnum + 1, &rset, NULL, NULL, &tv)) < 0)
+ goto error;
+ else if (retval == 0)
+ throw new ::java::io::InterruptedIOException ();
+ }
+
+ retlen =
+ ::recvfrom (fnum, (char *) dbytes, p->getLength(), 0, (sockaddr*) &u,
+ &addrlen);
+ if (retlen < 0)
+ goto error;
+ // FIXME: Deal with Multicast addressing and if the socket is connected.
+ jbyteArray raddr;
+ jint rport;
+ if (u.address.sin_family == AF_INET)
+ {
+ raddr = JvNewByteArray (4);
+ memcpy (elements (raddr), &u.address.sin_addr, 4);
+ rport = ntohs (u.address.sin_port);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ raddr = JvNewByteArray (16);
+ memcpy (elements (raddr), &u.address6.sin6_addr, 16);
+ rport = ntohs (u.address6.sin6_port);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
+
+ p->setAddress (new ::java::net::InetAddress (raddr, NULL));
+ p->setPort (rport);
+ p->setLength ((jint) retlen);
+ return;
+
+ error:
+ char* strerr = strerror (errno);
+
+ if (errno == ECONNREFUSED)
+ throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
+
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl)
+{
+ // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
+ char val = (char) ttl;
+ socklen_t val_len = sizeof(val);
+
+ if (::setsockopt (fnum, IPPROTO_IP, IP_MULTICAST_TTL, &val, val_len) == 0)
+ return;
+
+ char* strerr = strerror (errno);
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+}
+
+jint
+gnu::java::net::PlainDatagramSocketImpl::getTimeToLive ()
+{
+ // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
+ char val;
+ socklen_t val_len = sizeof(val);
+
+ if (::getsockopt (fnum, IPPROTO_IP, IP_MULTICAST_TTL, &val, &val_len) == 0)
+ return ((int) val) & 0xFF;
+
+ char* strerr = strerror (errno);
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::mcastGrp (::java::net::InetAddress *inetaddr,
+ ::java::net::NetworkInterface *,
+ jboolean join)
+{
+ // FIXME: implement use of NetworkInterface
+
+ union McastReq u;
+ jbyteArray haddress = inetaddr->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+ int level, opname;
+ const char *ptr;
+ if (0)
+ ;
+#if HAVE_STRUCT_IP_MREQ
+ else if (len == 4)
+ {
+ level = IPPROTO_IP;
+ opname = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+ memcpy (&u.mreq.imr_multiaddr, bytes, len);
+ // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
+ // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
+ u.mreq.imr_interface.s_addr = htonl (INADDR_ANY);
+ len = sizeof (struct ip_mreq);
+ ptr = (const char *) &u.mreq;
+ }
+#endif
+#if HAVE_STRUCT_IPV6_MREQ
+ else if (len == 16)
+ {
+ level = IPPROTO_IPV6;
+
+ /* Prefer new RFC 2553 names. */
+#ifndef IPV6_JOIN_GROUP
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#endif
+#ifndef IPV6_LEAVE_GROUP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#endif
+
+ opname = join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP;
+ memcpy (&u.mreq6.ipv6mr_multiaddr, bytes, len);
+ // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
+ // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
+ u.mreq6.ipv6mr_interface = 0;
+ len = sizeof (struct ipv6_mreq);
+ ptr = (const char *) &u.mreq6;
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (::setsockopt (fnum, level, opname, ptr, len) == 0)
+ return;
+
+ char* strerr = strerror (errno);
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::setOption (jint optID,
+ ::java::lang::Object *value)
+{
+ int val;
+ socklen_t val_len = sizeof (val);
+
+ if (fnum < 0)
+ throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
+
+ if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
+ {
+ ::java::lang::Boolean *boolobj =
+ static_cast< ::java::lang::Boolean *> (value);
+ val = boolobj->booleanValue() ? 1 : 0;
+ }
+ else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
+ {
+ ::java::lang::Integer *intobj =
+ static_cast< ::java::lang::Integer *> (value);
+ val = (int) intobj->intValue();
+ }
+ // Else assume value to be an InetAddress for use with IP_MULTICAST_IF.
+
+ switch (optID)
+ {
+ case _Jv_TCP_NODELAY_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
+ return;
+ case _Jv_SO_LINGER_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_LINGER not valid for UDP"));
+ return;
+ case _Jv_SO_KEEPALIVE_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
+ return;
+
+ case _Jv_SO_BROADCAST_ :
+ if (::setsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &val,
+ val_len) != 0)
+ goto error;
+ break;
+
+ case _Jv_SO_OOBINLINE_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_OOBINLINE: not valid for UDP"));
+ break;
+
+ case _Jv_SO_SNDBUF_ :
+ case _Jv_SO_RCVBUF_ :
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+ int opt;
+ optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+ if (::setsockopt (fnum, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
+ goto error;
+#else
+ throw new ::java::lang::InternalError (
+ JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
+#endif
+ return;
+ case _Jv_SO_REUSEADDR_ :
+#if defined(SO_REUSEADDR)
+ if (::setsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
+ val_len) != 0)
+ goto error;
+#else
+ throw new ::java::lang::InternalError (
+ JvNewStringUTF ("SO_REUSEADDR not supported"));
+#endif
+ return;
+ case _Jv_SO_BINDADDR_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_BINDADDR: read only option"));
+ return;
+ case _Jv_IP_MULTICAST_IF_ :
+ union InAddr u;
+ jbyteArray haddress;
+ jbyte *bytes;
+ int len;
+ int level, opname;
+ const char *ptr;
+
+ haddress = ((::java::net::InetAddress *) value)->addr;
+ bytes = elements (haddress);
+ len = haddress->length;
+ if (len == 4)
+ {
+ level = IPPROTO_IP;
+ opname = IP_MULTICAST_IF;
+ memcpy (&u.addr, bytes, len);
+ len = sizeof (struct in_addr);
+ ptr = (const char *) &u.addr;
+ }
+// Tru64 UNIX V5.0 has struct sockaddr_in6, but no IPV6_MULTICAST_IF
+#if defined (HAVE_INET6) && defined (IPV6_MULTICAST_IF)
+ else if (len == 16)
+ {
+ level = IPPROTO_IPV6;
+ opname = IPV6_MULTICAST_IF;
+ memcpy (&u.addr6, bytes, len);
+ len = sizeof (struct in6_addr);
+ ptr = (const char *) &u.addr6;
+ }
+#endif
+ else
+ throw
+ new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (::setsockopt (fnum, level, opname, ptr, len) != 0)
+ goto error;
+ return;
+
+ case _Jv_IP_MULTICAST_IF2_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
+ break;
+
+ case _Jv_IP_MULTICAST_LOOP_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_LOOP: not yet implemented"));
+ break;
+
+ case _Jv_IP_TOS_ :
+ if (::setsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
+ val_len) != 0)
+ goto error;
+ return;
+
+ case _Jv_SO_TIMEOUT_ :
+ timeout = val;
+ return;
+ default :
+ errno = ENOPROTOOPT;
+ }
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::SocketException (JvNewStringUTF (strerr));
+}
+
+::java::lang::Object *
+gnu::java::net::PlainDatagramSocketImpl::getOption (jint optID)
+{
+ int val;
+ socklen_t val_len = sizeof(val);
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+
+ switch (optID)
+ {
+ case _Jv_TCP_NODELAY_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
+ break;
+ case _Jv_SO_LINGER_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_LINGER not valid for UDP"));
+ break;
+ case _Jv_SO_KEEPALIVE_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
+ break;
+
+ case _Jv_SO_BROADCAST_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Boolean (val != 0);
+
+ case _Jv_SO_OOBINLINE_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_OOBINLINE not valid for UDP"));
+ break;
+
+ case _Jv_SO_RCVBUF_ :
+ case _Jv_SO_SNDBUF_ :
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+ int opt;
+ optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+ if (::getsockopt (fnum, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
+ goto error;
+ else
+ return new ::java::lang::Integer (val);
+#else
+ throw new ::java::lang::InternalError (
+ JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
+#endif
+ break;
+ case _Jv_SO_BINDADDR_:
+ // cache the local address
+ if (localAddress == NULL)
+ {
+ jbyteArray laddr;
+ if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
+ goto error;
+ if (u.address.sin_family == AF_INET)
+ {
+ laddr = JvNewByteArray (4);
+ memcpy (elements (laddr), &u.address.sin_addr, 4);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ laddr = JvNewByteArray (16);
+ memcpy (elements (laddr), &u.address6.sin6_addr, 16);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("invalid family"));
+ localAddress = new ::java::net::InetAddress (laddr, NULL);
+ }
+ return localAddress;
+ break;
+ case _Jv_SO_REUSEADDR_ :
+#if defined(SO_REUSEADDR)
+ if (::getsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Boolean (val != 0);
+#else
+ throw new ::java::lang::InternalError (
+ JvNewStringUTF ("SO_REUSEADDR not supported"));
+#endif
+ break;
+ case _Jv_IP_MULTICAST_IF_ :
+#ifdef HAVE_INET_NTOA
+ struct in_addr inaddr;
+ socklen_t inaddr_len;
+ char *bytes;
+
+ inaddr_len = sizeof(inaddr);
+ if (::getsockopt (fnum, IPPROTO_IP, IP_MULTICAST_IF, (char *) &inaddr,
+ &inaddr_len) != 0)
+ goto error;
+
+ bytes = inet_ntoa (inaddr);
+
+ return ::java::net::InetAddress::getByName (JvNewStringLatin1 (bytes));
+#else
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF: not available - no inet_ntoa()"));
+#endif
+ break;
+ case _Jv_SO_TIMEOUT_ :
+ return new ::java::lang::Integer (timeout);
+ break;
+
+ case _Jv_IP_MULTICAST_IF2_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
+ break;
+
+ case _Jv_IP_MULTICAST_LOOP_ :
+ if (::getsockopt (fnum, SOL_SOCKET, IP_MULTICAST_LOOP, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Boolean (val != 0);
+
+ case _Jv_IP_TOS_ :
+ if (::getsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Integer (val);
+
+ default :
+ errno = ENOPROTOOPT;
+ }
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::SocketException (JvNewStringUTF (strerr));
+}
diff --git a/libjava/gnu/java/net/natPlainDatagramSocketImplWin32.cc b/libjava/gnu/java/net/natPlainDatagramSocketImplWin32.cc
new file mode 100644
index 0000000..ae4b092
--- /dev/null
+++ b/libjava/gnu/java/net/natPlainDatagramSocketImplWin32.cc
@@ -0,0 +1,704 @@
+/* Copyright (C) 2003 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+#include <platform.h>
+#include <string.h>
+
+#if HAVE_BSTRING_H
+// Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2
+#include <bstring.h>
+#endif
+
+#include <gnu/java/net/PlainDatagramSocketImpl.h>
+#include <java/io/IOException.h>
+#include <java/io/InterruptedIOException.h>
+#include <java/net/BindException.h>
+#include <java/net/SocketException.h>
+#include <java/net/InetAddress.h>
+#include <java/net/NetworkInterface.h>
+#include <java/net/DatagramPacket.h>
+#include <java/net/PortUnreachableException.h>
+#include <java/net/SocketTimeoutException.h>
+#include <java/lang/InternalError.h>
+#include <java/lang/Object.h>
+#include <java/lang/Boolean.h>
+#include <java/lang/Integer.h>
+
+union SockAddr
+{
+ struct sockaddr_in address;
+#ifdef HAVE_INET6
+ struct sockaddr_in6 address6;
+#endif
+};
+
+union McastReq
+{
+#if HAVE_STRUCT_IP_MREQ
+ struct ip_mreq mreq;
+#endif
+#if HAVE_STRUCT_IPV6_MREQ
+ struct ipv6_mreq mreq6;
+#endif
+};
+
+union InAddr
+{
+ struct in_addr addr;
+#ifdef HAVE_INET6
+ struct in6_addr addr6;
+#endif
+};
+
+// FIXME: routines here and/or in natPlainSocketImpl.cc could throw
+// NoRouteToHostException; also consider UnknownHostException, ConnectException.
+
+void
+gnu::java::net::PlainDatagramSocketImpl::create ()
+{
+ SOCKET sock = ::socket (AF_INET, SOCK_DGRAM, 0);
+
+ if (sock == INVALID_SOCKET)
+ {
+ _Jv_ThrowSocketException ();
+ }
+
+ _Jv_platform_close_on_exec (sock);
+
+ // We use fnum in place of fd here. From leaving fd null we avoid
+ // the double close problem in FileDescriptor.finalize.
+ fnum = (int) sock;
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::bind (jint lport,
+ ::java::net::InetAddress *host)
+{
+ union SockAddr u;
+ struct sockaddr *ptr = (struct sockaddr *) &u.address;
+ // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4.
+ jbyteArray haddress = host->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+
+ if (host != NULL)
+ memcpy (&u.address.sin_addr, bytes, len);
+ else
+ u.address.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ len = sizeof (struct sockaddr_in);
+ u.address.sin_port = htons (lport);
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ u.address6.sin6_family = AF_INET6;
+ memcpy (&u.address6.sin6_addr, bytes, len);
+ len = sizeof (struct sockaddr_in6);
+ u.address6.sin6_port = htons (lport);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (::bind (fnum, ptr, len) == 0)
+ {
+ socklen_t addrlen = sizeof(u);
+
+ if (lport != 0)
+ localPort = lport;
+ else if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0)
+ localPort = ntohs (u.address.sin_port);
+ else
+ goto error;
+
+ /* Allow broadcast by default. */
+ int broadcast = 1;
+ if (::setsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &broadcast,
+ sizeof (broadcast)) != 0)
+ goto error;
+
+ return;
+ }
+
+error:
+ DWORD dwErrorCode = WSAGetLastError ();
+ throw new ::java::net::BindException (_Jv_WinStrError (dwErrorCode));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::connect (::java::net::InetAddress *, jint)
+{
+ throw new ::java::lang::InternalError (JvNewStringLatin1 (
+ "PlainDatagramSocketImpl::connect: not implemented yet"));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::disconnect ()
+{
+ throw new ::java::lang::InternalError (JvNewStringLatin1 (
+ "PlainDatagramSocketImpl::disconnect: not implemented yet"));
+}
+
+jint
+gnu::java::net::PlainDatagramSocketImpl::peek (::java::net::InetAddress *i)
+{
+ // FIXME: Deal with Multicast and if the socket is connected.
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ ssize_t retlen =
+ ::recvfrom (fnum, (char *) NULL, 0, MSG_PEEK, (sockaddr*) &u,
+ &addrlen);
+ if (retlen < 0)
+ goto error;
+ // FIXME: Deal with Multicast addressing and if the socket is connected.
+ jbyteArray raddr;
+ jint rport;
+ if (u.address.sin_family == AF_INET)
+ {
+ raddr = JvNewByteArray (4);
+ memcpy (elements (raddr), &u.address.sin_addr, 4);
+ rport = ntohs (u.address.sin_port);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ raddr = JvNewByteArray (16);
+ memcpy (elements (raddr), &u.address6.sin6_addr, 16);
+ rport = ntohs (u.address6.sin6_port);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
+
+ i->addr = raddr;
+ return rport;
+error:
+ DWORD dwErrorCode = WSAGetLastError ();
+ if (dwErrorCode == WSAECONNRESET)
+ throw new ::java::net::PortUnreachableException (_Jv_WinStrError (dwErrorCode));
+
+ _Jv_ThrowIOException ();
+ return -1;
+ // we should never get here
+}
+
+jint
+gnu::java::net::PlainDatagramSocketImpl::peekData(::java::net::DatagramPacket *p)
+{
+ // FIXME: Deal with Multicast and if the socket is connected.
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ jbyte *dbytes = elements (p->getData());
+ ssize_t retlen = 0;
+
+ if (timeout > 0)
+ {
+ int nRet= ::setsockopt(fnum, SOL_SOCKET, SO_RCVTIMEO,
+ (char*)&timeout, sizeof(timeout));
+ if (nRet != NO_ERROR)
+ goto error;
+ }
+
+ retlen =
+ ::recvfrom (fnum, (char *) dbytes, p->getLength(), MSG_PEEK, (sockaddr*) &u,
+ &addrlen);
+ if (retlen == SOCKET_ERROR)
+ goto error;
+ // FIXME: Deal with Multicast addressing and if the socket is connected.
+ jbyteArray raddr;
+ jint rport;
+ if (u.address.sin_family == AF_INET)
+ {
+ raddr = JvNewByteArray (4);
+ memcpy (elements (raddr), &u.address.sin_addr, 4);
+ rport = ntohs (u.address.sin_port);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ raddr = JvNewByteArray (16);
+ memcpy (elements (raddr), &u.address6.sin6_addr, 16);
+ rport = ntohs (u.address6.sin6_port);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
+
+ p->setAddress (new InetAddress (raddr, NULL));
+ p->setPort (rport);
+ p->setLength ((jint) retlen);
+ return rport;
+
+error:
+ DWORD dwErrorCode = WSAGetLastError ();
+ if (dwErrorCode == WSAECONNRESET)
+ throw new ::java::net::PortUnreachableException (_Jv_WinStrError (dwErrorCode));
+ else if (dwErrorCode == WSAETIMEDOUT)
+ throw new ::java::net::SocketTimeoutException (_Jv_WinStrError (dwErrorCode));
+ else
+ _Jv_ThrowIOException ();
+
+ return -1;
+ // we should never get here
+}
+
+// Close(shutdown) the socket.
+void
+gnu::java::net::PlainDatagramSocketImpl::close ()
+{
+ // Avoid races from asynchronous finalization.
+ JvSynchronize sync (this);
+
+ // The method isn't declared to throw anything, so we disregard
+ // the return value.
+ ::closesocket (fnum);
+ fnum = -1;
+ timeout = 0;
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::send (::java::net::DatagramPacket *p)
+{
+ // FIXME: Deal with Multicast and if the socket is connected.
+ jint rport = p->getPort();
+ union SockAddr u;
+ jbyteArray haddress = p->getAddress()->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+ struct sockaddr *ptr = (struct sockaddr *) &u.address;
+ jbyte *dbytes = elements (p->getData());
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+ memcpy (&u.address.sin_addr, bytes, len);
+ len = sizeof (struct sockaddr_in);
+ u.address.sin_port = htons (rport);
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ u.address6.sin6_family = AF_INET6;
+ memcpy (&u.address6.sin6_addr, bytes, len);
+ len = sizeof (struct sockaddr_in6);
+ u.address6.sin6_port = htons (rport);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (::sendto (fnum, (char *) dbytes, p->getLength(), 0, ptr, len) >= 0)
+ return;
+
+ DWORD dwErrorCode = WSAGetLastError ();
+ if (dwErrorCode == WSAECONNRESET)
+ throw new ::java::net::PortUnreachableException (_Jv_WinStrError (dwErrorCode));
+
+ _Jv_ThrowIOException ();
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::receive (::java::net::DatagramPacket *p)
+{
+ // FIXME: Deal with Multicast and if the socket is connected.
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ jbyte *dbytes = elements (p->getData());
+ ssize_t retlen = 0;
+
+ if (timeout > 0)
+ {
+ // This implementation doesn't allow specifying an infinite
+ // timeout after specifying a finite one, but Sun's JDK 1.4.1
+ // didn't seem to allow this either....
+ int nRet= ::setsockopt(fnum, SOL_SOCKET, SO_RCVTIMEO,
+ (char*)&timeout, sizeof(timeout));
+ if (nRet != NO_ERROR)
+ goto error;
+ }
+
+ retlen =
+ ::recvfrom (fnum, (char *) dbytes, p->getLength(), 0, (sockaddr*) &u,
+ &addrlen);
+ if (retlen < 0)
+ goto error;
+ // FIXME: Deal with Multicast addressing and if the socket is connected.
+ jbyteArray raddr;
+ jint rport;
+ if (u.address.sin_family == AF_INET)
+ {
+ raddr = JvNewByteArray (4);
+ memcpy (elements (raddr), &u.address.sin_addr, 4);
+ rport = ntohs (u.address.sin_port);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ raddr = JvNewByteArray (16);
+ memcpy (elements (raddr), &u.address6.sin6_addr, 16);
+ rport = ntohs (u.address6.sin6_port);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
+
+ p->setAddress (new ::java::net::InetAddress (raddr, NULL));
+ p->setPort (rport);
+ p->setLength ((jint) retlen);
+ return;
+
+ error:
+ DWORD dwErrorCode = WSAGetLastError();
+ if (dwErrorCode == WSAECONNRESET)
+ throw new ::java::net::PortUnreachableException (_Jv_WinStrError (dwErrorCode));
+ else if (dwErrorCode == WSAETIMEDOUT)
+ throw new ::java::net::SocketTimeoutException (_Jv_WinStrError (dwErrorCode));
+ else
+ throw new ::java::io::IOException (_Jv_WinStrError (dwErrorCode));
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl)
+{
+ // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
+ char val = (char) ttl;
+ socklen_t val_len = sizeof(val);
+
+ if (::setsockopt (fnum, IPPROTO_IP, IP_MULTICAST_TTL, &val, val_len) == 0)
+ return;
+
+ _Jv_ThrowIOException ();
+}
+
+jint
+gnu::java::net::PlainDatagramSocketImpl::getTimeToLive ()
+{
+ // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
+ char val;
+ socklen_t val_len = sizeof(val);
+
+ if (::getsockopt (fnum, IPPROTO_IP, IP_MULTICAST_TTL, &val, &val_len) == 0)
+ return ((int) val) & 0xFF;
+
+ _Jv_ThrowIOException ();
+
+ return -1;
+ // we should never get here
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::mcastGrp (::java::net::InetAddress *inetaddr,
+ ::java::net::NetworkInterface *,
+ jboolean join)
+{
+ // FIXME: implement use of NetworkInterface
+ jbyteArray haddress = inetaddr->addr;
+ int len = haddress->length;
+ int level, opname;
+ const char *ptr;
+ if (0)
+ ;
+#if HAVE_STRUCT_IP_MREQ
+ else if (len == 4)
+ {
+ level = IPPROTO_IP;
+ opname = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+ memcpy (&u.mreq.imr_multiaddr, bytes, len);
+ // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
+ // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
+ u.mreq.imr_interface.s_addr = htonl (INADDR_ANY);
+ len = sizeof (struct ip_mreq);
+ ptr = (const char *) &u.mreq;
+ }
+#endif
+#if HAVE_STRUCT_IPV6_MREQ
+ else if (len == 16)
+ {
+ level = IPPROTO_IPV6;
+
+ /* Prefer new RFC 2553 names. */
+#ifndef IPV6_JOIN_GROUP
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#endif
+#ifndef IPV6_LEAVE_GROUP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#endif
+
+ opname = join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP;
+ memcpy (&u.mreq6.ipv6mr_multiaddr, bytes, len);
+ // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
+ // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
+ u.mreq6.ipv6mr_interface = 0;
+ len = sizeof (struct ipv6_mreq);
+ ptr = (const char *) &u.mreq6;
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (::setsockopt (fnum, level, opname, ptr, len) == 0)
+ return;
+
+ _Jv_ThrowIOException ();
+}
+
+void
+gnu::java::net::PlainDatagramSocketImpl::setOption (jint optID,
+ ::java::lang::Object *value)
+{
+ int val;
+ socklen_t val_len = sizeof (val);
+
+ if (fnum < 0)
+ throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
+
+ if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
+ {
+ ::java::lang::Boolean *boolobj =
+ static_cast< ::java::lang::Boolean *> (value);
+ val = boolobj->booleanValue() ? 1 : 0;
+ }
+ else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
+ {
+ ::java::lang::Integer *intobj =
+ static_cast< ::java::lang::Integer *> (value);
+ val = (int) intobj->intValue();
+ }
+ // Else assume value to be an InetAddress for use with IP_MULTICAST_IF.
+
+ switch (optID)
+ {
+ case _Jv_TCP_NODELAY_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
+ return;
+ case _Jv_SO_LINGER_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_LINGER not valid for UDP"));
+ return;
+ case _Jv_SO_KEEPALIVE_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
+ return;
+
+ case _Jv_SO_BROADCAST_ :
+ if (::setsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &val,
+ val_len) != 0)
+ goto error;
+ break;
+
+ case _Jv_SO_OOBINLINE_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_OOBINLINE: not valid for UDP"));
+ break;
+
+ case _Jv_SO_SNDBUF_ :
+ case _Jv_SO_RCVBUF_ :
+ int opt;
+ optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+ if (::setsockopt (fnum, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
+ goto error;
+ return;
+ case _Jv_SO_REUSEADDR_ :
+ if (::setsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
+ val_len) != 0)
+ goto error;
+ return;
+ case _Jv_SO_BINDADDR_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_BINDADDR: read only option"));
+ return;
+ case _Jv_IP_MULTICAST_IF_ :
+ union InAddr u;
+ jbyteArray haddress;
+ jbyte *bytes;
+ int len;
+ int level, opname;
+ const char *ptr;
+
+ haddress = ((::java::net::InetAddress *) value)->addr;
+ bytes = elements (haddress);
+ len = haddress->length;
+ if (len == 4)
+ {
+ level = IPPROTO_IP;
+ opname = IP_MULTICAST_IF;
+ memcpy (&u.addr, bytes, len);
+ len = sizeof (struct in_addr);
+ ptr = (const char *) &u.addr;
+ }
+// Tru64 UNIX V5.0 has struct sockaddr_in6, but no IPV6_MULTICAST_IF
+#if defined (HAVE_INET6) && defined (IPV6_MULTICAST_IF)
+ else if (len == 16)
+ {
+ level = IPPROTO_IPV6;
+ opname = IPV6_MULTICAST_IF;
+ memcpy (&u.addr6, bytes, len);
+ len = sizeof (struct in6_addr);
+ ptr = (const char *) &u.addr6;
+ }
+#endif
+ else
+ throw
+ new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (::setsockopt (fnum, level, opname, ptr, len) != 0)
+ goto error;
+ return;
+
+ case _Jv_IP_MULTICAST_IF2_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
+ break;
+
+ case _Jv_IP_MULTICAST_LOOP_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_LOOP: not yet implemented"));
+ break;
+
+ case _Jv_IP_TOS_ :
+ if (::setsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
+ val_len) != 0)
+ goto error;
+ return;
+
+ case _Jv_SO_TIMEOUT_ :
+ timeout = val;
+ return;
+ default :
+ WSASetLastError (WSAENOPROTOOPT);
+ }
+
+ error:
+ _Jv_ThrowSocketException ();
+}
+
+::java::lang::Object *
+gnu::java::net::PlainDatagramSocketImpl::getOption (jint optID)
+{
+ int val;
+ socklen_t val_len = sizeof(val);
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+
+ switch (optID)
+ {
+ case _Jv_TCP_NODELAY_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
+ break;
+ case _Jv_SO_LINGER_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_LINGER not valid for UDP"));
+ break;
+ case _Jv_SO_KEEPALIVE_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
+ break;
+
+ case _Jv_SO_BROADCAST_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Boolean (val != 0);
+
+ case _Jv_SO_OOBINLINE_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_OOBINLINE not valid for UDP"));
+ break;
+
+ case _Jv_SO_RCVBUF_ :
+ case _Jv_SO_SNDBUF_ :
+ int opt;
+ optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+ if (::getsockopt (fnum, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
+ goto error;
+ else
+ return new ::java::lang::Integer (val);
+ break;
+ case _Jv_SO_BINDADDR_:
+ // cache the local address
+ if (localAddress == NULL)
+ {
+ jbyteArray laddr;
+ if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
+ goto error;
+ if (u.address.sin_family == AF_INET)
+ {
+ laddr = JvNewByteArray (4);
+ memcpy (elements (laddr), &u.address.sin_addr, 4);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ laddr = JvNewByteArray (16);
+ memcpy (elements (laddr), &u.address6.sin6_addr, 16);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("invalid family"));
+ localAddress = new ::java::net::InetAddress (laddr, NULL);
+ }
+ return localAddress;
+ break;
+ case _Jv_SO_REUSEADDR_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Boolean (val != 0);
+ break;
+ case _Jv_IP_MULTICAST_IF_ :
+ struct in_addr inaddr;
+ socklen_t inaddr_len;
+ char *bytes;
+
+ inaddr_len = sizeof(inaddr);
+ if (::getsockopt (fnum, IPPROTO_IP, IP_MULTICAST_IF, (char *) &inaddr,
+ &inaddr_len) != 0)
+ goto error;
+
+ bytes = inet_ntoa (inaddr);
+
+ return ::java::net::InetAddress::getByName (JvNewStringLatin1 (bytes));
+ break;
+ case _Jv_SO_TIMEOUT_ :
+ return new ::java::lang::Integer (timeout);
+ break;
+
+ case _Jv_IP_MULTICAST_IF2_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
+ break;
+
+ case _Jv_IP_MULTICAST_LOOP_ :
+ if (::getsockopt (fnum, SOL_SOCKET, IP_MULTICAST_LOOP, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Boolean (val != 0);
+
+ case _Jv_IP_TOS_ :
+ if (::getsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Integer (val);
+
+ default :
+ WSASetLastError (WSAENOPROTOOPT);
+ }
+
+error:
+ _Jv_ThrowSocketException ();
+ return 0;
+ // we should never get here
+}
diff --git a/libjava/gnu/java/net/natPlainSocketImplNoNet.cc b/libjava/gnu/java/net/natPlainSocketImplNoNet.cc
new file mode 100644
index 0000000..7465d63
--- /dev/null
+++ b/libjava/gnu/java/net/natPlainSocketImplNoNet.cc
@@ -0,0 +1,128 @@
+/* Copyright (C) 2003 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+#include <platform.h>
+
+#include <gnu/java/net/PlainSocketImpl.h>
+#include <java/io/IOException.h>
+#include <java/net/BindException.h>
+#include <java/net/ConnectException.h>
+#include <java/net/SocketException.h>
+
+void
+gnu::java::net::PlainSocketImpl::create (jboolean)
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("SocketImpl.create: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::bind (::java::net::InetAddress *, jint)
+{
+ throw new ::java::net::BindException (
+ JvNewStringLatin1 ("SocketImpl.bind: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::connect (::java::net::SocketAddress *, jint)
+{
+ throw new ::java::net::ConnectException (
+ JvNewStringLatin1 ("SocketImpl.connect: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::listen (jint)
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("SocketImpl.listen: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl *)
+{
+ throw new ::java::io::IOException (
+ JvNewStringLatin1 ("SocketImpl.accept: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::setOption (jint, ::java::lang::Object *)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.setOption: unimplemented"));
+}
+
+::java::lang::Object *
+gnu::java::net::PlainSocketImpl::getOption (jint)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.getOption: unimplemented"));
+}
+
+jint
+gnu::java::net::PlainSocketImpl::read(void)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.read: unimplemented"));
+}
+
+jint
+gnu::java::net::PlainSocketImpl::read(jbyteArray buffer, jint offset, jint count)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.read: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::write(jint b)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.write: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::write(jbyteArray b, jint offset, jint len)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.write: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::sendUrgentData(jint data)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.sendUrgentData: unimplemented"));
+}
+
+jint
+gnu::java::net::PlainSocketImpl::available(void)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.available: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::close(void)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.close: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::shutdownInput (void)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.shutdownInput: unimplemented"));
+}
+
+void
+gnu::java::net::PlainSocketImpl::shutdownOutput (void)
+{
+ throw new ::java::net::SocketException (
+ JvNewStringLatin1 ("SocketImpl.shutdownOutput: unimplemented"));
+}
diff --git a/libjava/gnu/java/net/natPlainSocketImplPosix.cc b/libjava/gnu/java/net/natPlainSocketImplPosix.cc
new file mode 100644
index 0000000..0b0bb1d
--- /dev/null
+++ b/libjava/gnu/java/net/natPlainSocketImplPosix.cc
@@ -0,0 +1,857 @@
+/* Copyright (C) 2003 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+#include <platform.h>
+
+#ifdef HAVE_SYS_IOCTL_H
+#define BSD_COMP /* Get FIONREAD on Solaris2. */
+#include <sys/ioctl.h>
+#endif
+
+// Pick up FIONREAD on Solaris 2.5.
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <errno.h>
+#include <string.h>
+
+#if HAVE_BSTRING_H
+// Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2
+#include <bstring.h>
+#endif
+
+#include <gcj/cni.h>
+#include <gcj/javaprims.h>
+#include <gnu/java/net/PlainSocketImpl.h>
+#include <java/io/IOException.h>
+#include <java/io/InterruptedIOException.h>
+#include <java/net/BindException.h>
+#include <java/net/ConnectException.h>
+#include <java/net/InetAddress.h>
+#include <java/net/InetSocketAddress.h>
+#include <java/net/SocketException.h>
+#include <java/net/SocketTimeoutException.h>
+#include <java/lang/InternalError.h>
+#include <java/lang/Object.h>
+#include <java/lang/Boolean.h>
+#include <java/lang/Class.h>
+#include <java/lang/Integer.h>
+#include <java/lang/Thread.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/ArrayIndexOutOfBoundsException.h>
+#include <java/lang/IllegalArgumentException.h>
+
+union SockAddr
+{
+ struct sockaddr_in address;
+#ifdef HAVE_INET6
+ struct sockaddr_in6 address6;
+#endif
+};
+
+void
+gnu::java::net::PlainSocketImpl::create (jboolean stream)
+{
+ int sock = _Jv_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
+
+ if (sock < 0)
+ {
+ char* strerr = strerror (errno);
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+ }
+
+ _Jv_platform_close_on_exec (sock);
+
+ // We use fnum in place of fd here. From leaving fd null we avoid
+ // the double close problem in FileDescriptor.finalize.
+ fnum = sock;
+}
+
+void
+gnu::java::net::PlainSocketImpl::bind (::java::net::InetAddress *host, jint lport)
+{
+ union SockAddr u;
+ struct sockaddr *ptr = (struct sockaddr *) &u.address;
+ jbyteArray haddress = host->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+ int i = 1;
+
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+
+ if (host != NULL)
+ memcpy (&u.address.sin_addr, bytes, len);
+ else
+ u.address.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ len = sizeof (struct sockaddr_in);
+ u.address.sin_port = htons (lport);
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ u.address6.sin6_family = AF_INET6;
+ memcpy (&u.address6.sin6_addr, bytes, len);
+ len = sizeof (struct sockaddr_in6);
+ u.address6.sin6_port = htons (lport);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ // Enable SO_REUSEADDR, so that servers can reuse ports left in TIME_WAIT.
+ ::setsockopt(fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof(i));
+
+ if (_Jv_bind (fnum, ptr, len) == 0)
+ {
+ address = host;
+ socklen_t addrlen = sizeof(u);
+
+ if (lport != 0)
+ localport = lport;
+ else if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0)
+ localport = ntohs (u.address.sin_port);
+ else
+ goto error;
+
+ return;
+ }
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::BindException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainSocketImpl::connect (::java::net::SocketAddress *addr,
+ jint timeout)
+{
+ ::java::net::InetSocketAddress *tmp = (::java::net::InetSocketAddress*) addr;
+ ::java::net::InetAddress *host = tmp->getAddress();
+ jint rport = tmp->getPort();
+
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ jbyteArray haddress = host->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+ struct sockaddr *ptr = (struct sockaddr *) &u.address;
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+ memcpy (&u.address.sin_addr, bytes, len);
+ len = sizeof (struct sockaddr_in);
+ u.address.sin_port = htons (rport);
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ u.address6.sin6_family = AF_INET6;
+ memcpy (&u.address6.sin6_addr, bytes, len);
+ len = sizeof (struct sockaddr_in6);
+ u.address6.sin6_port = htons (rport);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (timeout > 0)
+ {
+ int flags = ::fcntl (fnum, F_GETFL);
+ ::fcntl (fnum, F_SETFL, flags | O_NONBLOCK);
+
+ if ((_Jv_connect (fnum, ptr, len) != 0) && (errno != EINPROGRESS))
+ goto error;
+
+ fd_set fset;
+ struct timeval tv;
+ FD_ZERO(&fset);
+ FD_SET(fnum, &fset);
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ int retval;
+
+ if ((retval = _Jv_select (fnum + 1, &fset, &fset, NULL, &tv)) < 0)
+ goto error;
+ else if (retval == 0)
+ throw new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("Connect timed out"));
+ // Set the socket back into a blocking state.
+ ::fcntl (fnum, F_SETFL, flags);
+ }
+ else
+ {
+ if (_Jv_connect (fnum, ptr, len) != 0)
+ goto error;
+ }
+
+ address = host;
+ port = rport;
+
+ // A bind may not have been done on this socket; if so, set localport now.
+ if (localport == 0)
+ {
+ if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0)
+ localport = ntohs (u.address.sin_port);
+ else
+ goto error;
+ }
+
+ return;
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::ConnectException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainSocketImpl::listen (jint backlog)
+{
+ if (::listen (fnum, backlog) != 0)
+ {
+ char* strerr = strerror (errno);
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+ }
+}
+
+void
+gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl *s)
+{
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ int new_socket = 0;
+
+ // Do timeouts via select since SO_RCVTIMEO is not always available.
+ if (timeout > 0 && fnum >= 0 && fnum < FD_SETSIZE)
+ {
+ fd_set fset;
+ struct timeval tv;
+ FD_ZERO(&fset);
+ FD_SET(fnum, &fset);
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ int retval;
+ if ((retval = _Jv_select (fnum + 1, &fset, &fset, NULL, &tv)) < 0)
+ goto error;
+ else if (retval == 0)
+ throw new ::java::net::SocketTimeoutException (
+ JvNewStringUTF("Accept timed out"));
+ }
+
+ new_socket = _Jv_accept (fnum, (sockaddr*) &u, &addrlen);
+
+ if (new_socket < 0)
+ goto error;
+
+ _Jv_platform_close_on_exec (new_socket);
+
+ jbyteArray raddr;
+ jint rport;
+ if (u.address.sin_family == AF_INET)
+ {
+ raddr = JvNewByteArray (4);
+ memcpy (elements (raddr), &u.address.sin_addr, 4);
+ rport = ntohs (u.address.sin_port);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ raddr = JvNewByteArray (16);
+ memcpy (elements (raddr), &u.address6.sin6_addr, 16);
+ rport = ntohs (u.address6.sin6_port);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
+
+ s->fnum = new_socket;
+ s->localport = localport;
+ s->address = new ::java::net::InetAddress (raddr, NULL);
+ s->port = rport;
+ return;
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::io::IOException (JvNewStringUTF (strerr));
+}
+
+// Close(shutdown) the socket.
+void
+gnu::java::net::PlainSocketImpl::close()
+{
+ // Avoid races from asynchronous finalization.
+ JvSynchronize sync (this);
+
+ // should we use shutdown here? how would that effect so_linger?
+ int res = _Jv_close (fnum);
+
+ if (res == -1)
+ {
+ // These three errors are not errors according to tests performed
+ // on the reference implementation.
+ if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF)
+ throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
+ }
+ // Safe place to reset the file pointer.
+ fnum = -1;
+ timeout = 0;
+}
+
+// Write a byte to the socket.
+void
+gnu::java::net::PlainSocketImpl::write(jint b)
+{
+ jbyte d =(jbyte) b;
+ int r = 0;
+
+ while (r != 1)
+ {
+ r = _Jv_write (fnum, &d, 1);
+ if (r == -1)
+ {
+ if (::java::lang::Thread::interrupted())
+ {
+ ::java::io::InterruptedIOException *iioe
+ = new ::java::io::InterruptedIOException
+ (JvNewStringLatin1 (strerror (errno)));
+ iioe->bytesTransferred = 0;
+ throw iioe;
+ }
+ // Some errors should not cause exceptions.
+ if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF)
+ throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
+ break;
+ }
+ }
+}
+
+// Write some bytes to the socket.
+void
+gnu::java::net::PlainSocketImpl::write(jbyteArray b, jint offset, jint len)
+{
+ if (! b)
+ throw new ::java::lang::NullPointerException;
+ if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
+ throw new ::java::lang::ArrayIndexOutOfBoundsException;
+
+ jbyte *bytes = elements (b) + offset;
+ int written = 0;
+
+ while (len > 0)
+ {
+ int r = _Jv_write (fnum, bytes, len);
+
+ if (r == -1)
+ {
+ if (::java::lang::Thread::interrupted())
+ {
+ ::java::io::InterruptedIOException *iioe
+ = new ::java::io::InterruptedIOException
+ (JvNewStringLatin1 (strerror (errno)));
+ iioe->bytesTransferred = written;
+ throw iioe;
+ }
+ // Some errors should not cause exceptions.
+ if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF)
+ throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
+ break;
+ }
+
+ written += r;
+ len -= r;
+ bytes += r;
+ }
+}
+
+void
+gnu::java::net::PlainSocketImpl::sendUrgentData (jint)
+{
+ throw new ::java::net::SocketException (JvNewStringLatin1 (
+ "PlainSocketImpl: sending of urgent data not supported by this socket"));
+}
+
+// Read a single byte from the socket.
+jint
+gnu::java::net::PlainSocketImpl::read(void)
+{
+ jbyte b;
+
+ // Do timeouts via select.
+ if (timeout > 0 && fnum >= 0 && fnum < FD_SETSIZE)
+ {
+ // Create the file descriptor set.
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ FD_SET (fnum,&read_fds);
+ // Create the timeout struct based on our internal timeout value.
+ struct timeval timeout_value;
+ timeout_value.tv_sec = timeout / 1000;
+ timeout_value.tv_usec = (timeout % 1000) * 1000;
+ // Select on the fds.
+ int sel_retval =
+ _Jv_select (fnum + 1, &read_fds, NULL, NULL, &timeout_value);
+ // If select returns 0 we've waited without getting data...
+ // that means we've timed out.
+ if (sel_retval == 0)
+ throw new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("read timed out") );
+ // If select returns ok we know we either got signalled or read some data...
+ // either way we need to try to read.
+ }
+
+ int r = _Jv_read (fnum, &b, 1);
+
+ if (r == 0)
+ return -1;
+
+ if (::java::lang::Thread::interrupted())
+ {
+ ::java::io::InterruptedIOException *iioe =
+ new ::java::io::InterruptedIOException
+ (JvNewStringUTF("read interrupted"));
+ iioe->bytesTransferred = r == -1 ? 0 : r;
+ throw iioe;
+ }
+ else if (r == -1)
+ {
+ // Some errors cause us to return end of stream...
+ if (errno == ENOTCONN)
+ return -1;
+
+ // Other errors need to be signalled.
+ throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
+ }
+
+ return b & 0xFF;
+}
+
+// Read count bytes into the buffer, starting at offset.
+jint
+gnu::java::net::PlainSocketImpl::read(jbyteArray buffer, jint offset, jint count)
+{
+ if (! buffer)
+ throw new ::java::lang::NullPointerException;
+
+ jsize bsize = JvGetArrayLength (buffer);
+
+ if (offset < 0 || count < 0 || offset + count > bsize)
+ throw new ::java::lang::ArrayIndexOutOfBoundsException;
+
+ jbyte *bytes = elements (buffer) + offset;
+
+ // Do timeouts via select.
+ if (timeout > 0 && fnum >= 0 && fnum < FD_SETSIZE)
+ {
+ // Create the file descriptor set.
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ FD_SET (fnum, &read_fds);
+ // Create the timeout struct based on our internal timeout value.
+ struct timeval timeout_value;
+ timeout_value.tv_sec = timeout / 1000;
+ timeout_value.tv_usec =(timeout % 1000) * 1000;
+ // Select on the fds.
+ int sel_retval =
+ _Jv_select (fnum + 1, &read_fds, NULL, NULL, &timeout_value);
+ // We're only interested in the 0 return.
+ // error returns still require us to try to read
+ // the socket to see what happened.
+ if (sel_retval == 0)
+ {
+ ::java::net::SocketTimeoutException *timeoutException =
+ new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("read timed out"));
+ throw timeoutException;
+ }
+ }
+
+ // Read the socket.
+ int r = ::recv (fnum, (char *) bytes, count, 0);
+
+ if (r == 0)
+ return -1;
+
+ if (::java::lang::Thread::interrupted())
+ {
+ ::java::io::InterruptedIOException *iioe =
+ new ::java::io::InterruptedIOException
+ (JvNewStringUTF ("read interrupted"));
+ iioe->bytesTransferred = r == -1 ? 0 : r;
+ throw iioe;
+ }
+ else if (r == -1)
+ {
+ // Some errors cause us to return end of stream...
+ if (errno == ENOTCONN)
+ return -1;
+
+ // Other errors need to be signalled.
+ throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
+ }
+
+ return r;
+}
+
+// How many bytes are available?
+jint
+gnu::java::net::PlainSocketImpl::available(void)
+{
+#if defined(FIONREAD) || defined(HAVE_SELECT)
+ long num = 0;
+ int r = 0;
+ bool num_set = false;
+
+#if defined(FIONREAD)
+ r = ::ioctl (fnum, FIONREAD, &num);
+
+ if (r == -1 && errno == ENOTTY)
+ {
+ // If the ioctl doesn't work, we don't care.
+ r = 0;
+ num = 0;
+ }
+ else
+ num_set = true;
+#elif defined(HAVE_SELECT)
+ if (fnum < 0)
+ {
+ errno = EBADF;
+ r = -1;
+ }
+#endif
+
+ if (r == -1)
+ {
+ posix_error:
+ throw new ::java::io::IOException(JvNewStringUTF(strerror(errno)));
+ }
+
+ // If we didn't get anything we can use select.
+
+#if defined(HAVE_SELECT)
+ if (! num_set)
+ if (! num_set && fnum >= 0 && fnum < FD_SETSIZE)
+ {
+ fd_set rd;
+ FD_ZERO (&rd);
+ FD_SET (fnum, &rd);
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ r = _Jv_select (fnum + 1, &rd, NULL, NULL, &tv);
+ if(r == -1)
+ goto posix_error;
+ num = r == 0 ? 0 : 1;
+ }
+#endif /* HAVE_SELECT */
+
+ return (jint) num;
+#else
+ throw new ::java::io::IOException (JvNewStringUTF ("unimplemented"));
+#endif
+}
+
+void
+gnu::java::net::PlainSocketImpl::setOption (jint optID, ::java::lang::Object *value)
+{
+ int val;
+ socklen_t val_len = sizeof (val);
+
+ if (fnum < 0)
+ throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
+
+ if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
+ {
+ ::java::lang::Boolean *boolobj =
+ static_cast< ::java::lang::Boolean *> (value);
+ if (boolobj->booleanValue())
+ val = 1;
+ else
+ {
+ if (optID == _Jv_SO_LINGER_)
+ val = -1;
+ else
+ val = 0;
+ }
+ }
+ else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
+ {
+ ::java::lang::Integer *intobj =
+ static_cast< ::java::lang::Integer *> (value);
+ val = (int) intobj->intValue();
+ }
+ else
+ {
+ throw new ::java::lang::IllegalArgumentException (
+ JvNewStringLatin1 ("`value' must be Boolean or Integer"));
+ }
+
+ switch (optID)
+ {
+ case _Jv_TCP_NODELAY_ :
+#ifdef TCP_NODELAY
+ if (::setsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
+ val_len) != 0)
+ goto error;
+#else
+ throw new ::java::lang::InternalError
+ (JvNewStringUTF ("TCP_NODELAY not supported"));
+#endif /* TCP_NODELAY */
+ return;
+
+ case _Jv_SO_KEEPALIVE_ :
+ if (::setsockopt (fnum, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+ val_len) != 0)
+ goto error;
+ break;
+
+ case _Jv_SO_BROADCAST_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("SO_BROADCAST not valid for TCP"));
+ break;
+
+ case _Jv_SO_OOBINLINE_ :
+ if (::setsockopt (fnum, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
+ val_len) != 0)
+ goto error;
+ break;
+
+ case _Jv_SO_LINGER_ :
+#ifdef SO_LINGER
+ struct linger l_val;
+ l_val.l_onoff = (val != -1);
+ l_val.l_linger = val;
+
+ if (::setsockopt (fnum, SOL_SOCKET, SO_LINGER, (char *) &l_val,
+ sizeof(l_val)) != 0)
+ goto error;
+#else
+ throw new ::java::lang::InternalError (
+ JvNewStringUTF ("SO_LINGER not supported"));
+#endif /* SO_LINGER */
+ return;
+
+ case _Jv_SO_SNDBUF_ :
+ case _Jv_SO_RCVBUF_ :
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+ int opt;
+ optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+ if (::setsockopt (fnum, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
+ goto error;
+#else
+ throw new ::java::lang::InternalError (
+ JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
+#endif
+ return;
+
+ case _Jv_SO_BINDADDR_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_BINDADDR: read only option"));
+ return;
+
+ case _Jv_IP_MULTICAST_IF_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
+ return;
+
+ case _Jv_IP_MULTICAST_IF2_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
+ break;
+
+ case _Jv_IP_MULTICAST_LOOP_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
+ break;
+
+ case _Jv_IP_TOS_ :
+ if (::setsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
+ val_len) != 0)
+ goto error;
+ break;
+
+ case _Jv_SO_REUSEADDR_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"));
+ return;
+
+ case _Jv_SO_TIMEOUT_ :
+ timeout = val;
+ return;
+
+ default :
+ errno = ENOPROTOOPT;
+ }
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::SocketException (JvNewStringUTF (strerr));
+}
+
+::java::lang::Object *
+gnu::java::net::PlainSocketImpl::getOption (jint optID)
+{
+ int val;
+ socklen_t val_len = sizeof(val);
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ struct linger l_val;
+ socklen_t l_val_len = sizeof(l_val);
+
+ switch (optID)
+ {
+#ifdef TCP_NODELAY
+ case _Jv_TCP_NODELAY_ :
+ if (::getsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ else
+ return new ::java::lang::Boolean (val != 0);
+#else
+ throw new ::java::lang::InternalError
+ (JvNewStringUTF ("TCP_NODELAY not supported"));
+#endif
+ break;
+
+ case _Jv_SO_LINGER_ :
+#ifdef SO_LINGER
+ if (::getsockopt (fnum, SOL_SOCKET, SO_LINGER, (char *) &l_val,
+ &l_val_len) != 0)
+ goto error;
+
+ if (l_val.l_onoff)
+ return new ::java::lang::Integer (l_val.l_linger);
+ else
+ return new ::java::lang::Boolean ((jboolean)false);
+#else
+ throw new ::java::lang::InternalError
+ (JvNewStringUTF ("SO_LINGER not supported"));
+#endif
+ break;
+
+ case _Jv_SO_KEEPALIVE_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ else
+ return new ::java::lang::Boolean (val != 0);
+
+ case _Jv_SO_BROADCAST_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Boolean ((jboolean)val);
+
+ case _Jv_SO_OOBINLINE_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Boolean ((jboolean)val);
+
+ case _Jv_SO_RCVBUF_ :
+ case _Jv_SO_SNDBUF_ :
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+ int opt;
+ optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+ if (::getsockopt (fnum, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
+ goto error;
+ else
+ return new ::java::lang::Integer (val);
+#else
+ throw new ::java::lang::InternalError
+ (JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
+#endif
+ break;
+ case _Jv_SO_BINDADDR_:
+ // cache the local address
+ if (localAddress == NULL)
+ {
+ jbyteArray laddr;
+
+ if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
+ goto error;
+
+ if (u.address.sin_family == AF_INET)
+ {
+ laddr = JvNewByteArray (4);
+ memcpy (elements (laddr), &u.address.sin_addr, 4);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ laddr = JvNewByteArray (16);
+ memcpy (elements (laddr), &u.address6.sin6_addr, 16);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("invalid family"));
+ localAddress = new ::java::net::InetAddress (laddr, NULL);
+ }
+
+ return localAddress;
+ break;
+ case _Jv_IP_MULTICAST_IF_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
+ break;
+
+ case _Jv_IP_MULTICAST_IF2_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
+ break;
+
+ case _Jv_IP_MULTICAST_LOOP_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
+ break;
+
+ case _Jv_IP_TOS_ :
+ if (::getsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
+ &val_len) != 0)
+ goto error;
+ return new ::java::lang::Integer (val);
+ break;
+
+ case _Jv_SO_REUSEADDR_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"));
+ break;
+
+ case _Jv_SO_TIMEOUT_ :
+ return new ::java::lang::Integer (timeout);
+ break;
+
+ default :
+ errno = ENOPROTOOPT;
+ }
+
+ error:
+ char* strerr = strerror (errno);
+ throw new ::java::net::SocketException (JvNewStringUTF (strerr));
+}
+
+void
+gnu::java::net::PlainSocketImpl::shutdownInput (void)
+{
+ if (::shutdown (fnum, 0))
+ throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno)));
+}
+
+void
+gnu::java::net::PlainSocketImpl::shutdownOutput (void)
+{
+ if (::shutdown (fnum, 1))
+ throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno)));
+}
diff --git a/libjava/gnu/java/net/natPlainSocketImplWin32.cc b/libjava/gnu/java/net/natPlainSocketImplWin32.cc
new file mode 100644
index 0000000..e4837ed
--- /dev/null
+++ b/libjava/gnu/java/net/natPlainSocketImplWin32.cc
@@ -0,0 +1,784 @@
+/* Copyright (C) 2003 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+#include <platform.h>
+
+#undef STRICT
+#undef MAX_PRIORITY
+#undef MIN_PRIORITY
+
+#include <gnu/java/net/PlainSocketImpl.h>
+#include <java/io/IOException.h>
+#include <java/io/InterruptedIOException.h>
+#include <java/net/BindException.h>
+#include <java/net/ConnectException.h>
+#include <java/net/InetAddress.h>
+#include <java/net/InetSocketAddress.h>
+#include <java/net/SocketException.h>
+#include <java/net/SocketTimeoutException.h>
+#include <java/lang/InternalError.h>
+#include <java/lang/Object.h>
+#include <java/lang/Boolean.h>
+#include <java/lang/Class.h>
+#include <java/lang/Integer.h>
+#include <java/lang/Thread.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/ArrayIndexOutOfBoundsException.h>
+#include <java/lang/IllegalArgumentException.h>
+
+union SockAddr
+{
+ struct sockaddr_in address;
+#ifdef HAVE_INET6
+ struct sockaddr_in6 address6;
+#endif
+};
+
+void
+gnu::java::net::PlainSocketImpl::create (jboolean stream)
+{
+ int sock = ::socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
+
+ if (sock == int(INVALID_SOCKET))
+ {
+ _Jv_ThrowIOException ();
+ }
+
+ _Jv_platform_close_on_exec (sock);
+
+ // We use fnum in place of fd here. From leaving fd null we avoid
+ // the double close problem in FileDescriptor.finalize.
+ fnum = sock;
+}
+
+void
+gnu::java::net::PlainSocketImpl::bind (::java::net::InetAddress *host, jint lport)
+{
+ union SockAddr u;
+ struct sockaddr *ptr = (struct sockaddr *) &u.address;
+ jbyteArray haddress = host->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+ int i = 1;
+
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+
+ if (host != NULL)
+ memcpy (&u.address.sin_addr, bytes, len);
+ else
+ u.address.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ len = sizeof (struct sockaddr_in);
+ u.address.sin_port = htons (lport);
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ u.address6.sin6_family = AF_INET6;
+ memcpy (&u.address6.sin6_addr, bytes, len);
+ len = sizeof (struct sockaddr_in6);
+ u.address6.sin6_port = htons (lport);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ // Enable SO_REUSEADDR, so that servers can reuse ports left in TIME_WAIT.
+ ::setsockopt(fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof(i));
+
+ if (::bind (fnum, ptr, len) != SOCKET_ERROR)
+ {
+ address = host;
+ socklen_t addrlen = sizeof(u);
+
+ if (lport != 0)
+ localport = lport;
+ else if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != SOCKET_ERROR)
+ localport = ntohs (u.address.sin_port);
+ else
+ goto error;
+
+ return;
+ }
+
+error:
+ DWORD dwErrorCode = WSAGetLastError ();
+ throw new ::java::net::BindException (_Jv_WinStrError (dwErrorCode));
+}
+
+static void
+throwConnectException (DWORD dwErrorCode)
+{
+ throw new ::java::net::ConnectException (_Jv_WinStrError (dwErrorCode));
+}
+
+static void
+throwConnectException ()
+{
+ throwConnectException (WSAGetLastError ());
+}
+
+void
+gnu::java::net::PlainSocketImpl::connect (::java::net::SocketAddress *addr,
+ jint timeout)
+{
+ ::java::net::InetSocketAddress *tmp = (::java::net::InetSocketAddress*) addr;
+ ::java::net::InetAddress *host = tmp->getAddress();
+ jint rport = tmp->getPort();
+
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ jbyteArray haddress = host->addr;
+ jbyte *bytes = elements (haddress);
+ int len = haddress->length;
+ struct sockaddr *ptr = (struct sockaddr *) &u.address;
+
+ if (len == 4)
+ {
+ u.address.sin_family = AF_INET;
+ memcpy (&u.address.sin_addr, bytes, len);
+ len = sizeof (struct sockaddr_in);
+ u.address.sin_port = htons (rport);
+ }
+#ifdef HAVE_INET6
+ else if (len == 16)
+ {
+ u.address6.sin6_family = AF_INET6;
+ memcpy (&u.address6.sin6_addr, bytes, len);
+ len = sizeof (struct sockaddr_in6);
+ u.address6.sin6_port = htons (rport);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
+
+ if (timeout > 0)
+ {
+ // FIXME: we're creating a fresh WSAEVENT for each connect().
+ WSAEventWrapper aWSAEventWrapper(fnum, FD_CONNECT);
+ WSAEVENT hEvent = aWSAEventWrapper.getEventHandle ();
+
+ if (::connect (fnum, ptr, len) == SOCKET_ERROR)
+ {
+ if (WSAGetLastError () != WSAEWOULDBLOCK)
+ throwConnectException ();
+
+ DWORD dwRet =
+ WSAWaitForMultipleEvents (1, &hEvent, true, timeout, false);
+ // use true, false instead of TRUE, FALSE because the
+ // MS constants got undefined
+
+ if (dwRet == WSA_WAIT_FAILED)
+ throwConnectException ();
+
+ else if (dwRet == WSA_WAIT_TIMEOUT)
+ throw new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("connect timed out"));
+
+ // If we get here, we still need to check whether the actual
+ // connect() succeeded. Use any socket-specific error code
+ // instead of the thread-based one.
+ int nErrCode; int nErrLen=sizeof(nErrCode);
+ if (::getsockopt(fnum, SOL_SOCKET, SO_ERROR, (char*) &nErrCode,
+ &nErrLen) == SOCKET_ERROR)
+ {
+ throwConnectException ();
+ }
+
+ if (nErrCode != NO_ERROR)
+ {
+ throwConnectException (nErrCode);
+ }
+ }
+ }
+ else
+ {
+ if (::connect (fnum, ptr, len) == SOCKET_ERROR)
+ throwConnectException();
+ }
+
+ address = host;
+ port = rport;
+
+ // A bind may not have been done on this socket; if so, set localport now.
+ if (localport == 0)
+ {
+ if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != SOCKET_ERROR)
+ localport = ntohs (u.address.sin_port);
+ else
+ throwConnectException();
+ }
+}
+
+void
+gnu::java::net::PlainSocketImpl::listen (jint backlog)
+{
+ if (::listen (fnum, backlog) == SOCKET_ERROR)
+ {
+ _Jv_ThrowIOException ();
+ }
+}
+
+void
+gnu::java::net::PlainSocketImpl::accept (::java::net::PlainSocketImpl *s)
+{
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ int new_socket = 0;
+
+ if (timeout > 0)
+ {
+ // FIXME: we're creating a fresh WSAEVENT for each accept().
+ // One possible alternative would be that fnum really points
+ // to an extended structure consisting of the SOCKET, its
+ // associated WSAEVENT, etc.
+ WSAEventWrapper aWSAEventWrapper(fnum, FD_ACCEPT);
+ WSAEVENT hEvent = aWSAEventWrapper.getEventHandle ();
+
+ for (;;)
+ {
+ new_socket = ::accept (fnum, (sockaddr*) &u, &addrlen);
+
+ if (new_socket != int(INVALID_SOCKET))
+ {
+ // This new child socket is nonblocking because the parent
+ // socket became nonblocking via the WSAEventSelect() call,
+ // so we set its mode back to blocking.
+ WSAEventSelect (new_socket, hEvent, 0);
+ // undo the hEvent <-> FD_ACCEPT association inherited
+ // inherited from our parent socket
+
+ unsigned long lSockOpt = 0L;
+ // blocking mode
+ if (ioctlsocket(new_socket, FIONBIO, &lSockOpt) == SOCKET_ERROR)
+ {
+ goto error;
+ }
+ break;
+ }
+ else if (WSAGetLastError () != WSAEWOULDBLOCK)
+ {
+ goto error;
+ }
+
+ DWORD dwRet =
+ WSAWaitForMultipleEvents (1, &hEvent, true, timeout, false);
+ // use true, false instead of TRUE, FALSE because the
+ // MS constants got undefined
+
+ if (dwRet == WSA_WAIT_FAILED)
+ goto error;
+ else if (dwRet == WSA_WAIT_TIMEOUT)
+ throw new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("accept timed out"));
+ }
+ }
+ else
+ {
+ new_socket = ::accept (fnum, (sockaddr*) &u, &addrlen);
+ }
+
+ if (new_socket == int(INVALID_SOCKET))
+ goto error;
+
+ _Jv_platform_close_on_exec (new_socket);
+
+ jbyteArray raddr;
+ jint rport;
+ if (u.address.sin_family == AF_INET)
+ {
+ raddr = JvNewByteArray (4);
+ memcpy (elements (raddr), &u.address.sin_addr, 4);
+ rport = ntohs (u.address.sin_port);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ raddr = JvNewByteArray (16);
+ memcpy (elements (raddr), &u.address6.sin6_addr, 16);
+ rport = ntohs (u.address6.sin6_port);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
+
+ s->fnum = new_socket;
+ s->localport = localport;
+ s->address = new InetAddress (raddr, NULL);
+ s->port = rport;
+ return;
+
+ error:
+ _Jv_ThrowIOException ();
+}
+
+// Close(shutdown) the socket.
+void
+gnu::java::net::PlainSocketImpl::close()
+{
+ // Avoid races from asynchronous finalization.
+ JvSynchronize sync (this);
+
+ // should we use shutdown here? how would that effect so_linger?
+ int res = ::closesocket (fnum);
+
+ if (res == -1)
+ {
+ // These three errors are not errors according to tests performed
+ // on the reference implementation.
+ DWORD dwErr = WSAGetLastError();
+ if (dwErr != WSAENOTCONN && dwErr != WSAECONNRESET
+ && dwErr != WSAENOTSOCK)
+ _Jv_ThrowIOException ();
+ }
+ // Safe place to reset the file pointer.
+ fnum = -1;
+ timeout = 0;
+}
+
+// Write a byte to the socket.
+void
+gnu::java::net::PlainSocketImpl::write(jint b)
+{
+ jbyte d =(jbyte) b;
+ int r = 0;
+
+ while (r != 1)
+ {
+ r = ::send (fnum, (char*) &d, 1, 0);
+ if (r == -1)
+ {
+ DWORD dwErr = WSAGetLastError();
+ if (::java::lang::Thread::interrupted())
+ {
+ ::java::io::InterruptedIOException *iioe
+ = new ::java::io::InterruptedIOException
+ (_Jv_WinStrError (dwErr));
+ iioe->bytesTransferred = 0;
+ throw iioe;
+ }
+ // Some errors should not cause exceptions.
+ if (dwErr != WSAENOTCONN && dwErr != WSAECONNRESET
+ && dwErr != WSAENOTSOCK)
+ _Jv_ThrowIOException ();
+ break;
+ }
+ }
+}
+
+// Write some bytes to the socket.
+void
+gnu::java::net::PlainSocketImpl::write(jbyteArray b, jint offset, jint len)
+{
+ if (! b)
+ throw new ::java::lang::NullPointerException;
+ if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
+ throw new ::java::lang::ArrayIndexOutOfBoundsException;
+
+ jbyte *bytes = elements (b) + offset;
+ int written = 0;
+ while (len > 0)
+ {
+ int r = ::send (fnum, (char*) bytes, len, 0);
+
+ if (r == -1)
+ {
+ DWORD dwErr = WSAGetLastError();
+ if (::java::lang::Thread::interrupted())
+ {
+ ::java::io::InterruptedIOException *iioe
+ = new ::java::io::InterruptedIOException
+ (_Jv_WinStrError (dwErr));
+ iioe->bytesTransferred = written;
+ throw iioe;
+ }
+ // Some errors should not cause exceptions.
+ if (dwErr != WSAENOTCONN && dwErr != WSAECONNRESET
+ && dwErr != WSAENOTSOCK)
+ _Jv_ThrowIOException ();
+ break;
+ }
+
+ written += r;
+ len -= r;
+ bytes += r;
+ }
+}
+
+void
+gnu::java::net::PlainSocketImpl::sendUrgentData (jint)
+{
+ throw new ::java::net::SocketException (JvNewStringLatin1 (
+ "PlainSocketImpl: sending of urgent data not supported by this socket"));
+}
+
+// read() helper
+static jint
+doRead(int fnum, void* buf, int count, int timeout)
+{
+ int r = 0;
+ DWORD dwErrorCode = 0;
+ // we are forced to declare this here because
+ // a call to Thread::interrupted() blanks out
+ // WSAGetLastError().
+
+ // FIXME: we unconditionally set SO_RCVTIMEO here
+ // because we can't detect whether someone has
+ // gone from a non-zero to zero timeout. What we'd
+ // really need is a member state variable in addition
+ // to timeout
+ int nRet= ::setsockopt(fnum, SOL_SOCKET, SO_RCVTIMEO,
+ (char*)&timeout, sizeof(timeout));
+ if (nRet != NO_ERROR)
+ {
+ dwErrorCode = WSAGetLastError ();
+ goto error;
+ }
+
+ r = ::recv (fnum, (char*) buf, count, 0);
+
+ if (r == 0)
+ return -1;
+
+ dwErrorCode = WSAGetLastError ();
+ // save WSAGetLastError() before calling Thread.interrupted()
+
+ if (::java::lang::Thread::interrupted())
+ {
+ ::java::io::InterruptedIOException *iioe =
+ new ::java::io::InterruptedIOException
+ (JvNewStringUTF("read interrupted"));
+ iioe->bytesTransferred = r == -1 ? 0 : r;
+ throw iioe;
+ }
+ else if (r == -1)
+ {
+error:
+ // Some errors cause us to return end of stream...
+ if (dwErrorCode == WSAENOTCONN)
+ return -1;
+
+ // Other errors need to be signalled.
+ if (dwErrorCode == WSAETIMEDOUT)
+ throw new ::java::net::SocketTimeoutException
+ (JvNewStringUTF ("read timed out") );
+ else
+ _Jv_ThrowIOException (dwErrorCode);
+ }
+
+ return r;
+}
+
+// Read a single byte from the socket.
+jint
+gnu::java::net::PlainSocketImpl::read(void)
+{
+ jbyte b;
+ doRead(fnum, &b, 1, timeout);
+ return b & 0xFF;
+}
+
+// Read count bytes into the buffer, starting at offset.
+jint
+gnu::java::net::PlainSocketImpl::read(jbyteArray buffer, jint offset, jint count)
+{
+ if (! buffer)
+ throw new ::java::lang::NullPointerException;
+
+ jsize bsize = JvGetArrayLength (buffer);
+
+ if (offset < 0 || count < 0 || offset + count > bsize)
+ throw new ::java::lang::ArrayIndexOutOfBoundsException;
+
+ jbyte *bytes = elements (buffer) + offset;
+
+ // Read the socket.
+ return doRead(fnum, bytes, count, timeout);
+}
+
+// How many bytes are available?
+jint
+gnu::java::net::PlainSocketImpl::available(void)
+{
+ unsigned long num = 0;
+
+ if (::ioctlsocket (fnum, FIONREAD, &num) == SOCKET_ERROR)
+ _Jv_ThrowIOException ();
+
+ return (jint) num;
+}
+
+void
+gnu::java::net::PlainSocketImpl::setOption (jint optID, ::java::lang::Object *value)
+{
+ int val;
+ socklen_t val_len = sizeof (val);
+
+ if (fnum < 0)
+ throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
+
+ if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
+ {
+ ::java::lang::Boolean *boolobj =
+ static_cast< ::java::lang::Boolean *> (value);
+ if (boolobj->booleanValue())
+ val = 1;
+ else
+ {
+ if (optID == _Jv_SO_LINGER_)
+ val = -1;
+ else
+ val = 0;
+ }
+ }
+ else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
+ {
+ ::java::lang::Integer *intobj =
+ static_cast< ::java::lang::Integer *> (value);
+ val = (int) intobj->intValue();
+ }
+ else
+ {
+ throw new ::java::lang::IllegalArgumentException (
+ JvNewStringLatin1 ("`value' must be Boolean or Integer"));
+ }
+
+ switch (optID)
+ {
+ case _Jv_TCP_NODELAY_ :
+ if (::setsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
+ val_len) == SOCKET_ERROR)
+ goto error;
+ return;
+
+ case _Jv_SO_KEEPALIVE_ :
+ if (::setsockopt (fnum, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+ val_len) == SOCKET_ERROR)
+ goto error;
+ break;
+
+ case _Jv_SO_BROADCAST_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("SO_BROADCAST not valid for TCP"));
+ break;
+
+ case _Jv_SO_OOBINLINE_ :
+ if (::setsockopt (fnum, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
+ val_len) == SOCKET_ERROR)
+ goto error;
+ break;
+
+ case _Jv_SO_LINGER_ :
+ struct linger l_val;
+ l_val.l_onoff = (val != -1);
+ l_val.l_linger = val;
+
+ if (::setsockopt (fnum, SOL_SOCKET, SO_LINGER, (char *) &l_val,
+ sizeof(l_val)) == SOCKET_ERROR)
+ goto error;
+ return;
+
+ case _Jv_SO_SNDBUF_ :
+ case _Jv_SO_RCVBUF_ :
+ int opt;
+ optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+ if (::setsockopt (fnum, SOL_SOCKET, opt, (char *) &val,
+ val_len) == SOCKET_ERROR)
+ goto error;
+ return;
+
+ case _Jv_SO_BINDADDR_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_BINDADDR: read only option"));
+ return;
+
+ case _Jv_IP_MULTICAST_IF_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
+ return;
+
+ case _Jv_IP_MULTICAST_IF2_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
+ break;
+
+ case _Jv_IP_MULTICAST_LOOP_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
+ break;
+
+ case _Jv_IP_TOS_ :
+ if (::setsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
+ val_len) == SOCKET_ERROR)
+ goto error;
+ break;
+
+ case _Jv_SO_REUSEADDR_ :
+ throw new ::java::net::SocketException (
+ JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"));
+ return;
+
+ case _Jv_SO_TIMEOUT_ :
+ timeout = val;
+ return;
+
+ default :
+ WSASetLastError (WSAENOPROTOOPT);
+ }
+
+error:
+ _Jv_ThrowSocketException ();
+}
+
+::java::lang::Object *
+gnu::java::net::PlainSocketImpl::getOption (jint optID)
+{
+ int val;
+ socklen_t val_len = sizeof(val);
+ union SockAddr u;
+ socklen_t addrlen = sizeof(u);
+ struct linger l_val;
+ socklen_t l_val_len = sizeof(l_val);
+
+ switch (optID)
+ {
+ case _Jv_TCP_NODELAY_ :
+ if (::getsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
+ &val_len) == SOCKET_ERROR)
+ goto error;
+ else
+ return new ::java::lang::Boolean (val != 0);
+ break;
+
+ case _Jv_SO_LINGER_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_LINGER, (char *) &l_val,
+ &l_val_len) == SOCKET_ERROR)
+ goto error;
+
+ if (l_val.l_onoff)
+ return new ::java::lang::Integer (l_val.l_linger);
+ else
+ return new ::java::lang::Boolean ((jboolean)false);
+ break;
+
+ case _Jv_SO_KEEPALIVE_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+ &val_len) == SOCKET_ERROR)
+ goto error;
+ else
+ return new ::java::lang::Boolean (val != 0);
+
+ case _Jv_SO_BROADCAST_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &val,
+ &val_len) == SOCKET_ERROR)
+ goto error;
+ return new ::java::lang::Boolean ((jboolean)val);
+
+ case _Jv_SO_OOBINLINE_ :
+ if (::getsockopt (fnum, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
+ &val_len) == SOCKET_ERROR)
+ goto error;
+ return new ::java::lang::Boolean ((jboolean)val);
+
+ case _Jv_SO_RCVBUF_ :
+ case _Jv_SO_SNDBUF_ :
+ int opt;
+ optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
+ if (::getsockopt (fnum, SOL_SOCKET, opt, (char *) &val,
+ &val_len) == SOCKET_ERROR)
+ goto error;
+ else
+ return new ::java::lang::Integer (val);
+ break;
+ case _Jv_SO_BINDADDR_:
+ // cache the local address
+ if (localAddress == NULL)
+ {
+ jbyteArray laddr;
+
+ if (::getsockname (fnum, (sockaddr*) &u,
+ &addrlen) == SOCKET_ERROR)
+ goto error;
+
+ if (u.address.sin_family == AF_INET)
+ {
+ laddr = JvNewByteArray (4);
+ memcpy (elements (laddr), &u.address.sin_addr, 4);
+ }
+#ifdef HAVE_INET6
+ else if (u.address.sin_family == AF_INET6)
+ {
+ laddr = JvNewByteArray (16);
+ memcpy (elements (laddr), &u.address6.sin6_addr, 16);
+ }
+#endif
+ else
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("invalid family"));
+ localAddress = new ::java::net::InetAddress (laddr, NULL);
+ }
+
+ return localAddress;
+ break;
+ case _Jv_IP_MULTICAST_IF_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
+ break;
+
+ case _Jv_IP_MULTICAST_IF2_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
+ break;
+
+ case _Jv_IP_MULTICAST_LOOP_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
+ break;
+
+ case _Jv_IP_TOS_ :
+ if (::getsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
+ &val_len) == SOCKET_ERROR)
+ goto error;
+ return new ::java::lang::Integer (val);
+ break;
+
+ case _Jv_SO_REUSEADDR_ :
+ throw new ::java::net::SocketException
+ (JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"));
+ break;
+
+ case _Jv_SO_TIMEOUT_ :
+ return new ::java::lang::Integer (timeout);
+ break;
+
+ default :
+ WSASetLastError (WSAENOPROTOOPT);
+ }
+
+error:
+ _Jv_ThrowSocketException ();
+ return 0;
+ // we should never get here
+}
+
+void
+gnu::java::net::PlainSocketImpl::shutdownInput (void)
+{
+ if (::shutdown (fnum, 0))
+ _Jv_ThrowSocketException ();
+}
+
+void
+gnu::java::net::PlainSocketImpl::shutdownOutput (void)
+{
+ if (::shutdown (fnum, 1))
+ _Jv_ThrowSocketException ();
+}