diff options
Diffstat (limited to 'libjava/classpath/java/net/ServerSocket.java')
-rw-r--r-- | libjava/classpath/java/net/ServerSocket.java | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/libjava/classpath/java/net/ServerSocket.java b/libjava/classpath/java/net/ServerSocket.java new file mode 100644 index 000000000..1dbd7636c --- /dev/null +++ b/libjava/classpath/java/net/ServerSocket.java @@ -0,0 +1,627 @@ +/* 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; + private int port; + + /* + * This constructor is only used by java.nio. + */ + + ServerSocket(PlainSocketImpl impl) throws IOException + { + if (impl == null) + throw new NullPointerException("impl may not be null"); + + this.impl = impl; + this.impl.create(true); + setReuseAddress(true); + } + + /* + * This method is only used by java.nio. + */ + + 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 (isBound()) + throw new SocketException("Already bound"); + + InetAddress addr; + int port; + + if (endpoint == null) + { + addr = InetAddress.ANY_IF; + port = 0; + } + else if (! (endpoint instanceof InetSocketAddress)) + { + throw new IllegalArgumentException("Address type not supported"); + } + else + { + InetSocketAddress tmp = (InetSocketAddress) endpoint; + if (tmp.isUnresolved()) + throw new SocketException("Unresolved address"); + addr = tmp.getAddress(); + port = tmp.getPort(); + } + + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkListen(port); + + try + { + impl.bind(addr, port); + impl.listen(backlog); + this.port = port; + local = new InetSocketAddress( + (InetAddress) impl.getOption(SocketOptions.SO_BINDADDR), + impl.getLocalPort()); + } + finally + { + try + { + if (local == null) + close(); + } + catch (IOException _) + { + } + } + } + + /** + * 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; + } + catch (SecurityException 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"); + + // 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.bound = true; + socket.implCreated = true; + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkAccept(socket.getInetAddress().getHostAddress(), + socket.getPort()); + } + + /** + * Closes this socket and stops listening for connections + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + if (impl != null) + { + impl.close(); + impl = null; + } + } + + /** + * 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() + { + ServerSocketChannel channel = getChannel(); + return impl == null || (channel != null && ! channel.isOpen()); + } + + /** + * 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, Integer.valueOf(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, Integer.valueOf(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=" + + port + ",localport=" + 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 + { + if (factory != null) + throw new SocketException("SocketFactory already defined"); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSetFactory(); + + factory = fac; + } +} |