| /* ServerSocket.java -- Class for implementing server side sockets | |
| Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2006 | |
| 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., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 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 java.net; | |
| import gnu.java.net.PlainSocketImpl; | |
| import java.io.IOException; | |
| import java.nio.channels.IllegalBlockingModeException; | |
| import java.nio.channels.ServerSocketChannel; | |
| /* Written using on-line Java Platform 1.2 API Specification. | |
| * Status: I believe all methods are implemented. | |
| */ | |
| /** | |
| * This class models server side sockets. The basic model is that the | |
| * server socket is created and bound to some well known port. It then | |
| * listens for and accepts connections. At that point the client and | |
| * server sockets are ready to communicate with one another utilizing | |
| * whatever application layer protocol they desire. | |
| * | |
| * As with the <code>Socket</code> class, most instance methods of this class | |
| * simply redirect their calls to an implementation class. | |
| * | |
| * @author Aaron M. Renn (arenn@urbanophile.com) | |
| * @author Per Bothner (bothner@cygnus.com) | |
| */ | |
| public class ServerSocket | |
| { | |
| /** | |
| * This is the user defined SocketImplFactory, if one is supplied | |
| */ | |
| private static SocketImplFactory factory; | |
| /** | |
| * This is the SocketImp object to which most instance methods in this | |
| * class are redirected | |
| */ | |
| private SocketImpl impl; | |
| /** | |
| * We need to retain the local address even after the socket is closed. | |
| */ | |
| private InetSocketAddress local; | |
| /* | |
| * This constructor is only used by java.nio. | |
| */ | |
| // FIXME: Workaround a bug in gcj. | |
| //ServerSocket (PlainSocketImpl impl) throws IOException | |
| ServerSocket(SocketImpl impl) throws IOException | |
| { | |
| if (impl == null) | |
| throw new NullPointerException("impl may not be null"); | |
| this.impl = impl; | |
| this.impl.create(true); | |
| } | |
| /* | |
| * This method is only used by java.nio. | |
| */ | |
| // FIXME: Workaround a bug in gcj. | |
| //PlainSocketImpl getImpl() | |
| SocketImpl getImpl() | |
| { | |
| return impl; | |
| } | |
| /** | |
| * Constructor that simply sets the implementation. | |
| * | |
| * @exception IOException If an error occurs | |
| * | |
| * @specnote This constructor is public since JDK 1.4 | |
| */ | |
| public ServerSocket() throws IOException | |
| { | |
| if (factory != null) | |
| impl = factory.createSocketImpl(); | |
| else | |
| impl = new PlainSocketImpl(); | |
| impl.create(true); | |
| } | |
| /** | |
| * Creates a server socket and binds it to the specified port. If the | |
| * port number is 0, a random free port will be chosen. The pending | |
| * connection queue on this socket will be set to 50. | |
| * | |
| * @param port The port number to bind to | |
| * | |
| * @exception IOException If an error occurs | |
| * @exception SecurityException If a security manager exists and its | |
| * checkListen method doesn't allow the operation | |
| */ | |
| public ServerSocket(int port) throws IOException | |
| { | |
| this(port, 50); | |
| } | |
| /** | |
| * Creates a server socket and binds it to the specified port. If the | |
| * port number is 0, a random free port will be chosen. The pending | |
| * connection queue on this socket will be set to the value passed as | |
| * arg2. | |
| * | |
| * @param port The port number to bind to | |
| * @param backlog The length of the pending connection queue | |
| * | |
| * @exception IOException If an error occurs | |
| * @exception SecurityException If a security manager exists and its | |
| * checkListen method doesn't allow the operation | |
| */ | |
| public ServerSocket(int port, int backlog) throws IOException | |
| { | |
| this(port, backlog, null); | |
| } | |
| /** | |
| * Creates a server socket and binds it to the specified port. If the | |
| * port number is 0, a random free port will be chosen. The pending | |
| * connection queue on this socket will be set to the value passed as | |
| * backlog. The third argument specifies a particular local address to | |
| * bind t or null to bind to all local address. | |
| * | |
| * @param port The port number to bind to | |
| * @param backlog The length of the pending connection queue | |
| * @param bindAddr The address to bind to, or null to bind to all addresses | |
| * | |
| * @exception IOException If an error occurs | |
| * @exception SecurityException If a security manager exists and its | |
| * checkListen method doesn't allow the operation | |
| * | |
| * @since 1.1 | |
| */ | |
| public ServerSocket(int port, int backlog, InetAddress bindAddr) | |
| throws IOException | |
| { | |
| this(); | |
| // bind/listen socket | |
| bind(new InetSocketAddress(bindAddr, port), backlog); | |
| } | |
| /** | |
| * Binds the server socket to a specified socket address | |
| * | |
| * @param endpoint The socket address to bind to | |
| * | |
| * @exception IOException If an error occurs | |
| * @exception IllegalArgumentException If address type is not supported | |
| * @exception SecurityException If a security manager exists and its | |
| * checkListen method doesn't allow the operation | |
| * | |
| * @since 1.4 | |
| */ | |
| public void bind(SocketAddress endpoint) throws IOException | |
| { | |
| bind(endpoint, 50); | |
| } | |
| /** | |
| * Binds the server socket to a specified socket address | |
| * | |
| * @param endpoint The socket address to bind to | |
| * @param backlog The length of the pending connection queue | |
| * | |
| * @exception IOException If an error occurs | |
| * @exception IllegalArgumentException If address type is not supported | |
| * @exception SecurityException If a security manager exists and its | |
| * checkListen method doesn't allow the operation | |
| * | |
| * @since 1.4 | |
| */ | |
| public void bind(SocketAddress endpoint, int backlog) | |
| throws IOException | |
| { | |
| if (isClosed()) | |
| throw new SocketException("ServerSocket is closed"); | |
| if (! (endpoint instanceof InetSocketAddress)) | |
| throw new IllegalArgumentException("Address type not supported"); | |
| InetSocketAddress tmp = (InetSocketAddress) endpoint; | |
| SecurityManager s = System.getSecurityManager(); | |
| if (s != null) | |
| s.checkListen(tmp.getPort()); | |
| InetAddress addr = tmp.getAddress(); | |
| // Initialize addr with 0.0.0.0. | |
| if (addr == null) | |
| addr = InetAddress.ANY_IF; | |
| try | |
| { | |
| impl.bind(addr, tmp.getPort()); | |
| impl.listen(backlog); | |
| local = new InetSocketAddress( | |
| (InetAddress) impl.getOption(SocketOptions.SO_BINDADDR), | |
| impl.getLocalPort()); | |
| } | |
| catch (IOException exception) | |
| { | |
| close(); | |
| throw exception; | |
| } | |
| catch (RuntimeException exception) | |
| { | |
| close(); | |
| throw exception; | |
| } | |
| catch (Error error) | |
| { | |
| close(); | |
| throw error; | |
| } | |
| } | |
| /** | |
| * This method returns the local address to which this socket is bound | |
| * | |
| * @return The socket's local address | |
| */ | |
| public InetAddress getInetAddress() | |
| { | |
| if (local == null) | |
| return null; | |
| return local.getAddress(); | |
| } | |
| /** | |
| * This method returns the local port number to which this socket is bound | |
| * | |
| * @return The socket's port number | |
| */ | |
| public int getLocalPort() | |
| { | |
| if (local == null) | |
| return -1; | |
| return local.getPort(); | |
| } | |
| /** | |
| * Returns the local socket address | |
| * | |
| * @return the local socket address, null if not bound | |
| * | |
| * @since 1.4 | |
| */ | |
| public SocketAddress getLocalSocketAddress() | |
| { | |
| return local; | |
| } | |
| /** | |
| * Accepts a new connection and returns a connected <code>Socket</code> | |
| * instance representing that connection. This method will block until a | |
| * connection is available. | |
| * | |
| * @return socket object for the just accepted connection | |
| * | |
| * @exception IOException If an error occurs | |
| * @exception SecurityException If a security manager exists and its | |
| * checkListen method doesn't allow the operation | |
| * @exception IllegalBlockingModeException If this socket has an associated | |
| * channel, and the channel is in non-blocking mode | |
| * @exception SocketTimeoutException If a timeout was previously set with | |
| * setSoTimeout and the timeout has been reached | |
| */ | |
| public Socket accept() throws IOException | |
| { | |
| Socket socket = new Socket(); | |
| try | |
| { | |
| implAccept(socket); | |
| } | |
| catch (IOException e) | |
| { | |
| try | |
| { | |
| socket.close(); | |
| } | |
| catch (IOException e2) | |
| { | |
| // Ignore. | |
| } | |
| throw e; | |
| } | |
| return socket; | |
| } | |
| /** | |
| * This protected method is used to help subclasses override | |
| * <code>ServerSocket.accept()</code>. The passed in socket will be | |
| * connected when this method returns. | |
| * | |
| * @param socket The socket that is used for the accepted connection | |
| * | |
| * @exception IOException If an error occurs | |
| * @exception IllegalBlockingModeException If this socket has an associated | |
| * channel, and the channel is in non-blocking mode | |
| * | |
| * @since 1.1 | |
| */ | |
| protected final void implAccept(Socket socket) throws IOException | |
| { | |
| if (isClosed()) | |
| throw new SocketException("ServerSocket is closed"); | |
| // FIXME: Add a security check to make sure we're allowed to | |
| // connect to the remote host. | |
| // 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(); | |
| impl.accept(socket.impl); | |
| socket.implCreated = true; | |
| socket.bound = true; | |
| } | |
| /** | |
| * Closes this socket and stops listening for connections | |
| * | |
| * @exception IOException If an error occurs | |
| */ | |
| public void close() throws IOException | |
| { | |
| if (isClosed()) | |
| return; | |
| impl.close(); | |
| impl = null; | |
| if (getChannel() != null) | |
| getChannel().close(); | |
| } | |
| /** | |
| * Returns the unique <code>ServerSocketChannel</code> object | |
| * associated with this socket, if any. | |
| * | |
| * <p>The socket only has a <code>ServerSocketChannel</code> if its created | |
| * by <code>ServerSocketChannel.open()</code>.</p> | |
| * | |
| * @return the associated socket channel, null if none exists | |
| * | |
| * @since 1.4 | |
| */ | |
| public ServerSocketChannel getChannel() | |
| { | |
| return null; | |
| } | |
| /** | |
| * Returns true when the socket is bound, otherwise false | |
| * | |
| * @return true if socket is bound, false otherwise | |
| * | |
| * @since 1.4 | |
| */ | |
| public boolean isBound() | |
| { | |
| return local != null; | |
| } | |
| /** | |
| * Returns true if the socket is closed, otherwise false | |
| * | |
| * @return true if socket is closed, false otherwise | |
| * | |
| * @since 1.4 | |
| */ | |
| public boolean isClosed() | |
| { | |
| return impl == null; | |
| } | |
| /** | |
| * Sets the value of SO_TIMEOUT. A value of 0 implies that SO_TIMEOUT is | |
| * disabled (ie, operations never time out). This is the number of | |
| * milliseconds a socket operation can block before an | |
| * InterruptedIOException is thrown. | |
| * | |
| * @param timeout The new SO_TIMEOUT value | |
| * | |
| * @exception SocketException If an error occurs | |
| * | |
| * @since 1.1 | |
| */ | |
| public void setSoTimeout(int timeout) throws SocketException | |
| { | |
| if (isClosed()) | |
| throw new SocketException("ServerSocket is closed"); | |
| if (timeout < 0) | |
| throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0"); | |
| impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); | |
| } | |
| /** | |
| * Retrieves the current value of the SO_TIMEOUT setting. A value of 0 | |
| * implies that SO_TIMEOUT is disabled (ie, operations never time out). | |
| * This is the number of milliseconds a socket operation can block before | |
| * an InterruptedIOException is thrown. | |
| * | |
| * @return The value of SO_TIMEOUT | |
| * | |
| * @exception IOException If an error occurs | |
| * | |
| * @since 1.1 | |
| */ | |
| public int getSoTimeout() throws IOException | |
| { | |
| if (isClosed()) | |
| throw new SocketException("ServerSocket is closed"); | |
| Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT); | |
| if (! (timeout instanceof Integer)) | |
| throw new IOException("Internal Error"); | |
| return ((Integer) timeout).intValue(); | |
| } | |
| /** | |
| * Enables/Disables the SO_REUSEADDR option | |
| * | |
| * @param on 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 | |
| { | |
| if (isClosed()) | |
| throw new SocketException("ServerSocket is closed"); | |
| impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); | |
| } | |
| /** | |
| * 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 | |
| { | |
| if (isClosed()) | |
| throw new SocketException("ServerSocket is closed"); | |
| Object reuseaddr = impl.getOption(SocketOptions.SO_REUSEADDR); | |
| if (! (reuseaddr instanceof Boolean)) | |
| throw new SocketException("Internal Error"); | |
| return ((Boolean) reuseaddr).booleanValue(); | |
| } | |
| /** | |
| * This method sets the value for the system level socket option | |
| * SO_RCVBUF to the specified value. Note that valid values for this | |
| * option are specific to a given operating system. | |
| * | |
| * @param size The new receive buffer size. | |
| * | |
| * @exception SocketException If an error occurs or Socket is not connected | |
| * @exception IllegalArgumentException If size is 0 or negative | |
| * | |
| * @since 1.4 | |
| */ | |
| public void setReceiveBufferSize(int size) throws SocketException | |
| { | |
| if (isClosed()) | |
| throw new SocketException("ServerSocket is closed"); | |
| if (size <= 0) | |
| throw new IllegalArgumentException("SO_RCVBUF value must be > 0"); | |
| impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size)); | |
| } | |
| /** | |
| * This method returns the value of the system level socket option | |
| * SO_RCVBUF, which is used by the operating system to tune buffer | |
| * sizes for data transfers. | |
| * | |
| * @return The receive buffer size. | |
| * | |
| * @exception SocketException If an error occurs or Socket is not connected | |
| * | |
| * @since 1.4 | |
| */ | |
| public int getReceiveBufferSize() throws SocketException | |
| { | |
| if (isClosed()) | |
| throw new SocketException("ServerSocket is closed"); | |
| Object buf = impl.getOption(SocketOptions.SO_RCVBUF); | |
| if (! (buf instanceof Integer)) | |
| throw new SocketException("Internal Error: Unexpected type"); | |
| return ((Integer) buf).intValue(); | |
| } | |
| /** | |
| * Returns the value of this socket as a <code>String</code>. | |
| * | |
| * @return This socket represented as a <code>String</code>. | |
| */ | |
| public String toString() | |
| { | |
| if (! isBound()) | |
| return "ServerSocket[unbound]"; | |
| return ("ServerSocket[addr=" + getInetAddress() + ",port=" | |
| + impl.getPort() + ",localport=" + impl.getLocalPort() + "]"); | |
| } | |
| /** | |
| * Sets the <code>SocketImplFactory</code> for all | |
| * <code>ServerSocket</code>'s. This may only be done | |
| * once per virtual machine. Subsequent attempts will generate an | |
| * exception. Note that a <code>SecurityManager</code> check is made prior | |
| * to setting the factory. If insufficient privileges exist to set the | |
| * factory, an exception will be thrown | |
| * | |
| * @param fac the factory to set | |
| * | |
| * @exception SecurityException If this operation is not allowed by the | |
| * <code>SecurityManager</code>. | |
| * @exception SocketException If the factory object is already defined | |
| * @exception IOException If any other error occurs | |
| */ | |
| public static synchronized void setSocketFactory(SocketImplFactory fac) | |
| throws IOException | |
| { | |
| factory = fac; | |
| } | |
| } |