/* Socket.java -- Client socket implementation
- Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004
+ Free Software Foundation, Inc.
This file is part of GNU Classpath.
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
package java.net;
-import java.io.InputStream;
+import gnu.java.net.PlainSocketImpl;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.channels.SocketChannel;
import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.SocketChannel;
+
/* Written using on-line Java Platform 1.2 API Specification.
* Status: I believe all methods are implemented.
* <p>
* This class does not actually do any work. Instead, it redirects all of
* its calls to a socket implementation object which implements the
- * <code>SocketImpl</code> interface. The implementation class is
- * instantiated by factory class that implements the
+ * <code>SocketImpl</code> interface. The implementation class is
+ * instantiated by factory class that implements the
* <code>SocketImplFactory interface</code>. A default
* factory is provided, however the factory may be set by a call to
- * the <code>setSocketImplFactory</code> method. Note that this may only be
+ * the <code>setSocketImplFactory</code> method. Note that this may only be
* done once per virtual machine. If a subsequent attempt is made to set the
* factory, a <code>SocketException</code> will be thrown.
*
*/
public class Socket
{
-
- // Class Variables
-
/**
* This is the user SocketImplFactory for this class. If this variable is
* null, a default factory is used.
*/
static SocketImplFactory factory;
- // Instance Variables
-
/**
* The implementation object to which calls are redirected
*/
+ // package-private because ServerSocket.implAccept() needs to access it.
SocketImpl impl;
- private boolean inputShutdown;
- private boolean outputShutdown;
+ /**
+ * True if socket implementation was created by calling their
+ * create() method.
+ */
+ // package-private because ServerSocket.implAccept() needs to access it.
+ boolean implCreated;
+
+ /**
+ * True if the socket is bound.
+ */
+ private boolean bound;
- SocketChannel ch; // this field must have been set if created by SocketChannel
+ /**
+ * True if input is shutdown.
+ */
+ private boolean inputShutdown;
- private boolean closed = false;
+ /**
+ * True if output is shutdown.
+ */
+ private boolean outputShutdown;
/**
- * Initializes a new instance of <code>Socket</code> object without
- * connecting to a remote host. This useful for subclasses of socket that
+ * Initializes a new instance of <code>Socket</code> object without
+ * connecting to a remote host. This useful for subclasses of socket that
* might want this behavior.
*
* @specnote This constructor is public since JDK 1.4
* @since 1.1
*/
- public Socket ()
+ public Socket()
{
if (factory != null)
impl = factory.createSocketImpl();
else
impl = new PlainSocketImpl();
-
- inputShutdown = false;
- outputShutdown = false;
}
/**
* Initializes a new instance of <code>Socket</code> object without
* connecting to a remote host. This is useful for subclasses of socket
- * that might want this behavior.
+ * that might want this behavior.
* <p>
* Additionally, this socket will be created using the supplied
* implementation class instead the default class or one returned by a
- * factory. This value can be <code>null</code>, but if it is, all instance
- * methods in <code>Socket</code> should be overridden because most of them
- * rely on this value being populated.
+ * factory. If this value is <code>null</code>, the default Socket
+ * implementation is used.
*
* @param impl The <code>SocketImpl</code> to use for this
* <code>Socket</code>
*
* @since 1.1
*/
- protected Socket (SocketImpl impl) throws SocketException
+ protected Socket(SocketImpl impl) throws SocketException
{
- this.impl = impl;
- this.inputShutdown = false;
- this.outputShutdown = false;
+ if (impl == null)
+ this.impl = new PlainSocketImpl();
+ else
+ this.impl = impl;
}
/**
- * Initializes a new instance of <code>Socket</code> and connects to the
+ * Initializes a new instance of <code>Socket</code> and connects to the
* hostname and port specified as arguments.
*
* @param host The name of the host to connect to
* @exception SecurityException If a security manager exists and its
* checkConnect method doesn't allow the operation
*/
- public Socket (String host, int port)
+ public Socket(String host, int port)
throws UnknownHostException, IOException
{
this(InetAddress.getByName(host), port, null, 0, true);
}
/**
- * Initializes a new instance of <code>Socket</code> and connects to the
+ * Initializes a new instance of <code>Socket</code> and connects to the
* address and port number specified as arguments.
*
* @param address The address to connect to
* @exception SecurityException If a security manager exists and its
* checkConnect method doesn't allow the operation
*/
- public Socket (InetAddress address, int port)
- throws IOException
+ public Socket(InetAddress address, int port) throws IOException
{
this(address, port, null, 0, true);
}
/**
- * Initializes a new instance of <code>Socket</code> that connects to the
- * named host on the specified port and binds to the specified local address
+ * Initializes a new instance of <code>Socket</code> that connects to the
+ * named host on the specified port and binds to the specified local address
* and port.
*
* @param host The name of the remote host to connect to.
* @param port The remote port to connect to.
- * @param loadAddr The local address to bind to.
+ * @param localAddr The local address to bind to.
* @param localPort The local port to bind to.
*
* @exception SecurityException If the <code>SecurityManager</code>
*
* @since 1.1
*/
- public Socket (String host, int port,
- InetAddress localAddr, int localPort) throws IOException
+ public Socket(String host, int port, InetAddress localAddr, int localPort)
+ throws IOException
{
this(InetAddress.getByName(host), port, localAddr, localPort, true);
}
/**
- * Initializes a new instance of <code>Socket</code> and connects to the
- * address and port number specified as arguments, plus binds to the
+ * Initializes a new instance of <code>Socket</code> and connects to the
+ * address and port number specified as arguments, plus binds to the
* specified local address and port.
*
* @param address The remote address to connect to
*
* @since 1.1
*/
- public Socket (InetAddress address, int port,
- InetAddress localAddr, int localPort) throws IOException
+ public Socket(InetAddress address, int port, InetAddress localAddr,
+ int localPort) throws IOException
{
this(address, port, localAddr, localPort, true);
}
/**
- * Initializes a new instance of <code>Socket</code> and connects to the
- * hostname and port specified as arguments. If the stream argument is set
- * to <code>true</code>, then a stream socket is created. If it is
+ * Initializes a new instance of <code>Socket</code> and connects to the
+ * hostname and port specified as arguments. If the stream argument is set
+ * to <code>true</code>, then a stream socket is created. If it is
* <code>false</code>, a datagram socket is created.
*
* @param host The name of the host to connect to
* @deprecated Use the <code>DatagramSocket</code> class to create
* datagram oriented sockets.
*/
- public Socket (String host, int port, boolean stream) throws IOException
+ public Socket(String host, int port, boolean stream)
+ throws IOException
{
this(InetAddress.getByName(host), port, null, 0, stream);
}
/**
- * Initializes a new instance of <code>Socket</code> and connects to the
- * address and port number specified as arguments. If the stream param is
- * <code>true</code>, a stream socket will be created, otherwise a datagram
+ * Initializes a new instance of <code>Socket</code> and connects to the
+ * address and port number specified as arguments. If the stream param is
+ * <code>true</code>, a stream socket will be created, otherwise a datagram
* socket is created.
*
* @param host The address to connect to
* @param port The port number to connect to
- * @param stream <code>true</code> to create a stream socket,
+ * @param stream <code>true</code> to create a stream socket,
* <code>false</code> to create a datagram socket.
*
* @exception IOException If an error occurs
* @deprecated Use the <code>DatagramSocket</code> class to create
* datagram oriented sockets.
*/
- public Socket (InetAddress host, int port, boolean stream) throws IOException
+ public Socket(InetAddress host, int port, boolean stream)
+ throws IOException
{
this(host, port, null, 0, stream);
}
{
this();
- if (raddr == null)
- throw new NullPointerException ();
-
- if (impl == null)
- throw new IOException("Cannot initialize Socket implementation");
-
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkConnect(raddr.getHostName(), rport);
// bind socket
SocketAddress bindaddr =
- laddr == null ? null : new InetSocketAddress (laddr, lport);
- bind (bindaddr);
-
+ laddr == null ? null : new InetSocketAddress(laddr, lport);
+ bind(bindaddr);
+
// connect socket
- connect (new InetSocketAddress (raddr, rport));
+ connect(new InetSocketAddress(raddr, rport));
// FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port,
// i.e. '0' and if localAddr is unspecified, use getLocalAddress() as
// that default. JDK 1.2 doc infers not to do a bind.
}
+ private SocketImpl getImpl() throws SocketException
+ {
+ try
+ {
+ if (! implCreated)
+ {
+ impl.create(true);
+ implCreated = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw new SocketException(e.getMessage());
+ }
+
+ return impl;
+ }
+
/**
* Binds the socket to the givent local address/port
*
* @exception SecurityException If a security manager exists and its
* checkConnect method doesn't allow the operation
* @exception IllegalArgumentException If the address type is not supported
- *
+ *
* @since 1.4
*/
- public void bind (SocketAddress bindpoint) throws IOException
+ public void bind(SocketAddress bindpoint) throws IOException
{
- if (closed)
- throw new SocketException ("Socket is closed");
+ if (isClosed())
+ throw new SocketException("socket is closed");
// XXX: JDK 1.4.1 API documentation says that if bindpoint is null the
// socket will be bound to an ephemeral port and a valid local address.
if (bindpoint == null)
- bindpoint = new InetSocketAddress (InetAddress.ANY_IF, 0);
-
- if ( !(bindpoint instanceof InetSocketAddress))
- throw new IllegalArgumentException ();
+ bindpoint = new InetSocketAddress(InetAddress.ANY_IF, 0);
+
+ if (! (bindpoint instanceof InetSocketAddress))
+ throw new IllegalArgumentException();
InetSocketAddress tmp = (InetSocketAddress) bindpoint;
-
- // create socket
- impl.create (true);
-
+
// bind to address/port
try
{
- impl.bind (tmp.getAddress(), tmp.getPort());
+ getImpl().bind(tmp.getAddress(), tmp.getPort());
+ bound = true;
}
catch (IOException exception)
{
- impl.close ();
- throw exception;
+ close();
+ throw exception;
}
catch (RuntimeException exception)
{
- impl.close ();
- throw exception;
+ close();
+ throw exception;
}
catch (Error error)
{
- impl.close ();
- throw error;
+ close();
+ throw error;
}
}
-
+
/**
* Connects the socket with a remote address.
*
* @exception IllegalArgumentException If the addess type is not supported
* @exception IllegalBlockingModeException If this socket has an associated
* channel, and the channel is in non-blocking mode
- *
+ *
* @since 1.4
*/
- public void connect (SocketAddress endpoint)
- throws IOException
+ public void connect(SocketAddress endpoint) throws IOException
{
- connect (endpoint, 0);
+ connect(endpoint, 0);
}
/**
* until established or an error occurs.
*
* @param endpoint The address to connect to
+ * @param timeout The length of the timeout in milliseconds, or
+ * 0 to indicate no timeout.
*
* @exception IOException If an error occurs
* @exception IllegalArgumentException If the address type is not supported
* @exception IllegalBlockingModeException If this socket has an associated
* channel, and the channel is in non-blocking mode
* @exception SocketTimeoutException If the timeout is reached
- *
+ *
* @since 1.4
*/
- public void connect (SocketAddress endpoint, int timeout)
+ public void connect(SocketAddress endpoint, int timeout)
throws IOException
{
- if (closed)
- throw new SocketException ("Socket is closed");
-
+ if (isClosed())
+ throw new SocketException("socket is closed");
+
if (! (endpoint instanceof InetSocketAddress))
- throw new IllegalArgumentException ("Address type not supported");
+ throw new IllegalArgumentException("unsupported address type");
+
+ // The Sun spec says that if we have an associated channel and
+ // it is in non-blocking mode, we throw an IllegalBlockingModeException.
+ // However, in our implementation if the channel itself initiated this
+ // operation, then we must honor it regardless of its blocking mode.
+ if (getChannel() != null && ! getChannel().isBlocking()
+ && ! ((PlainSocketImpl) getImpl()).isInChannelOperation())
+ throw new IllegalBlockingModeException();
- if (ch != null && !ch.isBlocking ())
- throw new IllegalBlockingModeException ();
-
- if (!isBound ())
- bind (null);
+ if (! isBound())
+ bind(null);
try
{
- impl.connect (endpoint, timeout);
+ getImpl().connect(endpoint, timeout);
}
catch (IOException exception)
{
- impl.close ();
- throw exception;
+ close();
+ throw exception;
}
catch (RuntimeException exception)
{
- impl.close ();
- throw exception;
+ close();
+ throw exception;
}
catch (Error error)
{
- impl.close ();
- throw error;
+ close();
+ throw error;
}
}
*
* @return The remote address this socket is connected to
*/
- public InetAddress getInetAddress ()
+ public InetAddress getInetAddress()
{
- if (impl != null)
- return impl.getInetAddress();
+ if (! isConnected())
+ return null;
+
+ try
+ {
+ return getImpl().getInetAddress();
+ }
+ catch (SocketException e)
+ {
+ // This cannot happen as we are connected.
+ }
return null;
}
/**
* Returns the local address to which this socket is bound. If this socket
- * is not connected, then <code>null</code> is returned.
+ * is not connected, then a wildcard address, for which
+ * @see isAnyLocalAddress() is <code>true</code>, is returned.
*
* @return The local address
*
* @since 1.1
*/
- public InetAddress getLocalAddress ()
+ public InetAddress getLocalAddress()
{
- if (impl == null)
- return null;
+ if (! isBound())
+ return InetAddress.ANY_IF;
InetAddress addr = null;
+
try
{
- addr = (InetAddress)impl.getOption(SocketOptions.SO_BINDADDR);
+ addr = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
}
- catch(SocketException e)
+ catch (SocketException e)
{
- // (hopefully) shouldn't happen
- // throw new java.lang.InternalError
- // ("Error in PlainSocketImpl.getOption");
- return null;
+ // (hopefully) shouldn't happen
+ // throw new java.lang.InternalError
+ // ("Error in PlainSocketImpl.getOption");
+ return null;
}
// FIXME: According to libgcj, checkConnect() is supposed to be called
*
* @return The remote port this socket is connected to
*/
- public int getPort ()
+ public int getPort()
{
- if (impl != null)
- return impl.getPort();
+ if (! isConnected())
+ return -1;
+
+ try
+ {
+ return getImpl().getPort();
+ }
+ catch (SocketException e)
+ {
+ // This cannot happen as we are connected.
+ }
return -1;
}
*
* @return The local port
*/
- public int getLocalPort ()
+ public int getLocalPort()
{
- if (impl != null)
- return impl.getLocalPort();
+ if (! isBound())
+ return -1;
+
+ try
+ {
+ if (getImpl() != null)
+ return getImpl().getLocalPort();
+ }
+ catch (SocketException e)
+ {
+ // This cannot happen as we are bound.
+ }
return -1;
}
/**
- * If the socket is already bound this returns the local SocketAddress,
- * otherwise null
+ * Returns local socket address.
+ *
+ * @return the local socket address, null if not bound
*
* @since 1.4
*/
public SocketAddress getLocalSocketAddress()
{
- InetAddress addr = getLocalAddress ();
-
- if (addr == null)
+ if (! isBound())
return null;
-
- return new InetSocketAddress (addr, impl.getLocalPort());
+
+ InetAddress addr = getLocalAddress();
+
+ try
+ {
+ return new InetSocketAddress(addr, getImpl().getLocalPort());
+ }
+ catch (SocketException e)
+ {
+ // This cannot happen as we are bound.
+ return null;
+ }
}
/**
- * If the socket is already connected this returns the remote SocketAddress,
- * otherwise null
+ * Returns the remote socket address.
+ *
+ * @return the remote socket address, null of not connected
*
* @since 1.4
*/
public SocketAddress getRemoteSocketAddress()
{
- if (!isConnected ())
+ if (! isConnected())
return null;
- return new InetSocketAddress (impl.getInetAddress (), impl.getPort ());
+ try
+ {
+ return new InetSocketAddress(getImpl().getInetAddress(),
+ getImpl().getPort());
+ }
+ catch (SocketException e)
+ {
+ // This cannot happen as we are connected.
+ return null;
+ }
}
/**
*
* @exception IOException If an error occurs or Socket is not connected
*/
- public InputStream getInputStream () throws IOException
+ public InputStream getInputStream() throws IOException
{
- if (impl != null)
- return(impl.getInputStream());
+ if (isClosed())
+ throw new SocketException("socket is closed");
- throw new IOException("Not connected");
+ if (! isConnected())
+ throw new IOException("not connected");
+
+ return getImpl().getInputStream();
}
/**
*
* @exception IOException If an error occurs or Socket is not connected
*/
- public OutputStream getOutputStream () throws IOException
+ public OutputStream getOutputStream() throws IOException
{
- if (impl != null)
- return impl.getOutputStream();
+ if (isClosed())
+ throw new SocketException("socket is closed");
+
+ if (! isConnected())
+ throw new IOException("not connected");
- throw new IOException("Not connected");
+ return getImpl().getOutputStream();
}
/**
- * Sets the TCP_NODELAY option on the socket.
+ * Sets the TCP_NODELAY option on the socket.
*
* @param on true to enable, false to disable
- *
+ *
* @exception SocketException If an error occurs or Socket is not connected
*
* @since 1.1
*/
- public void setTcpNoDelay (boolean on) throws SocketException
+ public void setTcpNoDelay(boolean on) throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- impl.setOption(SocketOptions.TCP_NODELAY, new Boolean(on));
+ getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
}
/**
- * Tests whether or not the TCP_NODELAY option is set on the socket.
+ * Tests whether or not the TCP_NODELAY option is set on the socket.
* Returns true if enabled, false if disabled. When on it disables the
* Nagle algorithm which means that packets are always send immediatly and
* never merged together to reduce network trafic.
*
* @return Whether or not TCP_NODELAY is set
- *
+ *
* @exception SocketException If an error occurs or Socket not connected
*
* @since 1.1
*/
public boolean getTcpNoDelay() throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
+
+ Object on = getImpl().getOption(SocketOptions.TCP_NODELAY);
- Object on = impl.getOption(SocketOptions.TCP_NODELAY);
-
if (on instanceof Boolean)
- return(((Boolean)on).booleanValue());
+ return (((Boolean) on).booleanValue());
else
throw new SocketException("Internal Error");
}
/**
- * Sets the value of the SO_LINGER option on the socket. If the
+ * Sets the value of the SO_LINGER option on the socket. If the
* SO_LINGER option is set on a socket and there is still data waiting to
* be sent when the socket is closed, then the close operation will block
* until either that data is delivered or until the timeout period
* (platform specific?)
*
* @param on true to enable SO_LINGER, false to disable
- * @param linger The SO_LINGER timeout in hundreths of a second or -1 if
+ * @param linger The SO_LINGER timeout in hundreths of a second or -1 if
* SO_LINGER not set.
*
* @exception SocketException If an error occurs or Socket not connected
*/
public void setSoLinger(boolean on, int linger) throws SocketException
{
- if (impl == null)
- throw new SocketException("No socket created");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- if (on == true)
+ if (on)
{
- if (linger < 0)
- throw new IllegalArgumentException("SO_LINGER must be >= 0");
+ if (linger < 0)
+ throw new IllegalArgumentException("SO_LINGER must be >= 0");
- if (linger > 65535)
- linger = 65535;
+ if (linger > 65535)
+ linger = 65535;
- impl.setOption(SocketOptions.SO_LINGER, new Integer(linger));
+ getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger));
}
else
- {
- impl.setOption(SocketOptions.SO_LINGER, new Boolean(false));
- }
+ getImpl().setOption(SocketOptions.SO_LINGER, Boolean.valueOf(false));
}
/**
- * Returns the value of the SO_LINGER option on the socket. If the
+ * Returns the value of the SO_LINGER option on the socket. If the
* SO_LINGER option is set on a socket and there is still data waiting to
* be sent when the socket is closed, then the close operation will block
* until either that data is delivered or until the timeout period
* of a second (platform specific?)) if SO_LINGER is set, or -1 if
* SO_LINGER is not set.
*
- * @return The SO_LINGER timeout in hundreths of a second or -1
+ * @return The SO_LINGER timeout in hundreths of a second or -1
* if SO_LINGER not set
*
* @exception SocketException If an error occurs or Socket is not connected
*/
public int getSoLinger() throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
+
+ Object linger = getImpl().getOption(SocketOptions.SO_LINGER);
- Object linger = impl.getOption(SocketOptions.SO_LINGER);
if (linger instanceof Integer)
- return(((Integer)linger).intValue());
+ return (((Integer) linger).intValue());
else
return -1;
}
*
* @since 1.4
*/
- public void sendUrgentData (int data) throws IOException
+ public void sendUrgentData(int data) throws IOException
{
- impl.sendUrgentData (data);
+ if (isClosed())
+ throw new SocketException("socket is closed");
+
+ getImpl().sendUrgentData(data);
}
/**
* Enables/disables the SO_OOBINLINE option
- *
- * @param on True if SO_OOBLINE should be enabled
- *
+ *
+ * @param on True if SO_OOBLINE should be enabled
+ *
* @exception SocketException If an error occurs
- *
+ *
* @since 1.4
*/
- public void setOOBInline (boolean on) throws SocketException
+ public void setOOBInline(boolean on) throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- impl.setOption(SocketOptions.SO_OOBINLINE, new Boolean(on));
+ getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on));
}
/**
* Returns the current setting of the SO_OOBINLINE option for this socket
- *
+ *
+ * @return True if SO_OOBINLINE is set, false otherwise.
+ *
* @exception SocketException If an error occurs
- *
+ *
* @since 1.4
*/
- public boolean getOOBInline () throws SocketException
+ public boolean getOOBInline() throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- Object buf = impl.getOption(SocketOptions.SO_OOBINLINE);
+ Object buf = getImpl().getOption(SocketOptions.SO_OOBINLINE);
if (buf instanceof Boolean)
- return(((Boolean)buf).booleanValue());
+ return (((Boolean) buf).booleanValue());
else
throw new SocketException("Internal Error: Unexpected type");
}
-
+
/**
* Sets the value of the SO_TIMEOUT option on the socket. If this value
* is set, and an read/write is performed that does not complete within
* the timeout period, a short count is returned (or an EWOULDBLOCK signal
* would be sent in Unix if no data had been read). A value of 0 for
- * this option implies that there is no timeout (ie, operations will
+ * this option implies that there is no timeout (ie, operations will
* block forever). On systems that have separate read and write timeout
* values, this method returns the read timeout. This
* value is in milliseconds.
*
- * @param timeout The length of the timeout in milliseconds, or
+ * @param timeout The length of the timeout in milliseconds, or
* 0 to indicate no timeout.
*
* @exception SocketException If an error occurs or Socket not connected
*
* @since 1.1
*/
- public synchronized void setSoTimeout (int timeout) throws SocketException
+ public synchronized void setSoTimeout(int timeout) throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
-
+ if (isClosed())
+ throw new SocketException("socket is closed");
+
if (timeout < 0)
throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0");
-
- impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+
+ getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
}
/**
* is set, and an read/write is performed that does not complete within
* the timeout period, a short count is returned (or an EWOULDBLOCK signal
* would be sent in Unix if no data had been read). A value of 0 for
- * this option implies that there is no timeout (ie, operations will
+ * this option implies that there is no timeout (ie, operations will
* block forever). On systems that have separate read and write timeout
* values, this method returns the read timeout. This
* value is in thousandths of a second (implementation specific?).
*
- * @return The length of the timeout in thousandth's of a second or 0
+ * @return The length of the timeout in thousandth's of a second or 0
* if not set
*
* @exception SocketException If an error occurs or Socket not connected
*
* @since 1.1
*/
- public synchronized int getSoTimeout () throws SocketException
+ public synchronized int getSoTimeout() throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT);
+ Object timeout = getImpl().getOption(SocketOptions.SO_TIMEOUT);
if (timeout instanceof Integer)
- return(((Integer)timeout).intValue());
+ return (((Integer) timeout).intValue());
else
return 0;
}
*
* @since 1.2
*/
- public void setSendBufferSize (int size) throws SocketException
+ public void setSendBufferSize(int size) throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
-
+ if (isClosed())
+ throw new SocketException("socket is closed");
+
if (size <= 0)
throw new IllegalArgumentException("SO_SNDBUF value must be > 0");
-
- impl.setOption(SocketOptions.SO_SNDBUF, new Integer(size));
+
+ getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
}
/**
*
* @since 1.2
*/
- public int getSendBufferSize () throws SocketException
+ public int getSendBufferSize() throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- Object buf = impl.getOption(SocketOptions.SO_SNDBUF);
+ Object buf = getImpl().getOption(SocketOptions.SO_SNDBUF);
if (buf instanceof Integer)
- return(((Integer)buf).intValue());
+ return (((Integer) buf).intValue());
else
throw new SocketException("Internal Error: Unexpected type");
}
*
* @since 1.2
*/
- public void setReceiveBufferSize (int size) throws SocketException
+ public void setReceiveBufferSize(int size) throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
if (size <= 0)
throw new IllegalArgumentException("SO_RCVBUF value must be > 0");
-
- impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size));
+
+ getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
}
/**
*
* @since 1.2
*/
- public int getReceiveBufferSize () throws SocketException
+ public int getReceiveBufferSize() throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- Object buf = impl.getOption(SocketOptions.SO_RCVBUF);
+ Object buf = getImpl().getOption(SocketOptions.SO_RCVBUF);
if (buf instanceof Integer)
- return(((Integer)buf).intValue());
+ return (((Integer) buf).intValue());
else
throw new SocketException("Internal Error: Unexpected type");
}
*
* @since 1.3
*/
- public void setKeepAlive (boolean on) throws SocketException
+ public void setKeepAlive(boolean on) throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- impl.setOption(SocketOptions.SO_KEEPALIVE, new Boolean(on));
+ getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on));
}
/**
*
* @since 1.3
*/
- public boolean getKeepAlive () throws SocketException
+ public boolean getKeepAlive() throws SocketException
{
- if (impl == null)
- throw new SocketException("Not connected");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- Object buf = impl.getOption(SocketOptions.SO_KEEPALIVE);
+ Object buf = getImpl().getOption(SocketOptions.SO_KEEPALIVE);
if (buf instanceof Boolean)
- return(((Boolean)buf).booleanValue());
+ return (((Boolean) buf).booleanValue());
else
throw new SocketException("Internal Error: Unexpected type");
}
*
* @exception IOException If an error occurs
*/
- public synchronized void close () throws IOException
+ public synchronized void close() throws IOException
{
- if (impl != null)
- impl.close();
+ if (isClosed())
+ return;
- if (ch != null)
- ch.close();
-
- closed = true;
+ getImpl().close();
+ impl = null;
+ bound = false;
+
+ if (getChannel() != null)
+ getChannel().close();
}
/**
*
* @return The <code>String</code> representation of this <code>Socket</code>
*/
- public String toString ()
+ public String toString()
{
- return("Socket " + impl);
- }
+ try
+ {
+ if (isConnected())
+ return ("Socket[addr=" + getImpl().getInetAddress() + ",port="
+ + getImpl().getPort() + ",localport="
+ + getImpl().getLocalPort() + "]");
+ }
+ catch (SocketException e)
+ {
+ // This cannot happen as we are connected.
+ }
- // Class Methods
+ return "Socket[unconnected]";
+ }
/**
- * Sets the <code>SocketImplFactory</code>. This may be done only once per
- * virtual machine. Subsequent attempts will generate a
+ * Sets the <code>SocketImplFactory</code>. This may be done only once per
+ * virtual machine. Subsequent attempts will generate a
* <code>SocketException</code>. Note that a <code>SecurityManager</code>
- * check is made prior to setting the factory. If
- * insufficient privileges exist to set the factory, then an
+ * check is made prior to setting the factory. If
+ * insufficient privileges exist to set the factory, then an
* <code>IOException</code> will be thrown.
*
+ * @param fac the factory to set
+ *
* @exception SecurityException If the <code>SecurityManager</code> does
* not allow this operation.
* @exception SocketException If the SocketImplFactory is already defined
* @exception IOException If any other error occurs
*/
- public static synchronized void setSocketImplFactory (SocketImplFactory fac)
+ public static synchronized void setSocketImplFactory(SocketImplFactory fac)
throws IOException
{
// See if already set
*/
public void shutdownInput() throws IOException
{
- if (impl != null)
- impl.shutdownInput();
+ if (isClosed())
+ throw new SocketException("socket is closed");
+ getImpl().shutdownInput();
inputShutdown = true;
}
*/
public void shutdownOutput() throws IOException
{
- if (impl != null)
- impl.shutdownOutput();
-
+ if (isClosed())
+ throw new SocketException("socket is closed");
+
+ getImpl().shutdownOutput();
outputShutdown = true;
}
/**
* Returns the socket channel associated with this socket.
*
- * It returns null if no associated socket exists.
+ * @return the associated socket channel,
+ * null if no associated channel exists
*
* @since 1.4
*/
public SocketChannel getChannel()
{
- return ch;
+ return null;
}
/**
* Checks if the SO_REUSEADDR option is enabled
*
+ * @return True if SO_REUSEADDR is set, false otherwise.
+ *
* @exception SocketException If an error occurs
*
* @since 1.4
*/
- public boolean getReuseAddress () throws SocketException
+ public boolean getReuseAddress() throws SocketException
{
- if (impl == null)
- throw new SocketException ("Cannot initialize Socket implementation");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- Object reuseaddr = impl.getOption (SocketOptions.SO_REUSEADDR);
+ Object reuseaddr = getImpl().getOption(SocketOptions.SO_REUSEADDR);
- if (!(reuseaddr instanceof Boolean))
- throw new SocketException ("Internal Error");
+ if (! (reuseaddr instanceof Boolean))
+ throw new SocketException("Internal Error");
- return ((Boolean) reuseaddr).booleanValue ();
+ return ((Boolean) reuseaddr).booleanValue();
}
/**
* Enables/Disables the SO_REUSEADDR option
*
+ * @param reuseAddress true if SO_REUSEADDR should be enabled,
+ * false otherwise
+ *
* @exception SocketException If an error occurs
*
* @since 1.4
*/
- public void setReuseAddress (boolean on) throws SocketException
+ public void setReuseAddress(boolean reuseAddress) throws SocketException
{
- if (impl == null)
- throw new SocketException ("Cannot initialize Socket implementation");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- impl.setOption (SocketOptions.SO_REUSEADDR, new Boolean (on));
+ getImpl().setOption(SocketOptions.SO_REUSEADDR,
+ Boolean.valueOf(reuseAddress));
}
/**
* Returns the current traffic class
*
+ * @return The current traffic class.
+ *
* @exception SocketException If an error occurs
*
* @see Socket#setTrafficClass(int tc)
*
* @since 1.4
*/
- public int getTrafficClass () throws SocketException
+ public int getTrafficClass() throws SocketException
{
- if (impl == null)
- throw new SocketException ("Cannot initialize Socket implementation");
+ if (isClosed())
+ throw new SocketException("socket is closed");
- Object obj = impl.getOption(SocketOptions.IP_TOS);
+ Object obj = getImpl().getOption(SocketOptions.IP_TOS);
if (obj instanceof Integer)
- return ((Integer) obj).intValue ();
+ return ((Integer) obj).intValue();
else
- throw new SocketException ("Unexpected type");
+ throw new SocketException("Unexpected type");
}
/**
*
* @since 1.4
*/
- public void setTrafficClass (int tc) throws SocketException
+ public void setTrafficClass(int tc) throws SocketException
{
- if (impl == null)
- throw new SocketException ("Cannot initialize Socket implementation");
+ if (isClosed())
+ throw new SocketException("socket is closed");
if (tc < 0 || tc > 255)
throw new IllegalArgumentException();
- impl.setOption (SocketOptions.IP_TOS, new Integer (tc));
+ getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc));
}
/**
* Checks if the socket is connected
*
+ * @return True if socket is connected, false otherwise.
+ *
* @since 1.4
*/
- public boolean isConnected ()
+ public boolean isConnected()
{
- return impl.getInetAddress () != null;
+ try
+ {
+ if (getImpl() == null)
+ return false;
+
+ return getImpl().getInetAddress() != null;
+ }
+ catch (SocketException e)
+ {
+ return false;
+ }
}
/**
* Checks if the socket is already bound.
*
+ * @return True if socket is bound, false otherwise.
+ *
* @since 1.4
*/
- public boolean isBound ()
+ public boolean isBound()
{
- return getLocalAddress () != null;
+ return bound;
}
/**
* Checks if the socket is closed.
- *
+ *
+ * @return True if socket is closed, false otherwise.
+ *
* @since 1.4
*/
- public boolean isClosed ()
+ public boolean isClosed()
{
- return closed;
+ return impl == null;
}
/**
* Checks if the socket's input stream is shutdown
*
+ * @return True if input is shut down.
+ *
* @since 1.4
*/
- public boolean isInputShutdown ()
+ public boolean isInputShutdown()
{
return inputShutdown;
}
/**
* Checks if the socket's output stream is shutdown
*
+ * @return True if output is shut down.
+ *
* @since 1.4
*/
- public boolean isOutputShutdown ()
+ public boolean isOutputShutdown()
{
return outputShutdown;
}