ServerSocket.java revision 32c2297a959b72abdb18743f0519e1d8b7c7ea88
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.net;
19
20import java.io.IOException;
21import java.nio.channels.ServerSocketChannel;
22
23/**
24 * This class represents a server-side socket that waits for incoming client
25 * connections. A {@code ServerSocket} handles the requests and sends back an
26 * appropriate reply. The actual tasks that a server socket must accomplish are
27 * implemented by an internal {@code SocketImpl} instance.
28 */
29public class ServerSocket {
30
31    SocketImpl impl;
32
33    static SocketImplFactory factory;
34
35    private volatile boolean isCreated;
36
37    private boolean isBound;
38
39    private boolean isClosed;
40
41    /**
42     * Constructs a new {@code ServerSocket} instance which is not bound to any
43     * port. The default number of pending connections may be backlogged.
44     *
45     * @throws IOException
46     *             if an error occurs while creating the server socket.
47     */
48    public ServerSocket() throws IOException {
49        impl = factory != null ? factory.createSocketImpl()
50                : new PlainServerSocketImpl();
51    }
52
53    /**
54     * Unspecified constructor needed by ServerSocketChannelImpl.ServerSocketAdapter.
55     *
56     * @hide
57     */
58    protected ServerSocket(SocketImpl impl) {
59        this.impl = impl;
60    }
61
62    /**
63     * Constructs a new {@code ServerSocket} instance bound to the nominated
64     * port on the localhost. The default number of pending connections may be
65     * backlogged. If {@code aport} is 0 a free port is assigned to the socket.
66     *
67     * @param aport
68     *            the port number to listen for connection requests on.
69     * @throws IOException
70     *             if an error occurs while creating the server socket.
71     */
72    public ServerSocket(int aport) throws IOException {
73        this(aport, defaultBacklog(), Inet4Address.ANY);
74    }
75
76    /**
77     * Constructs a new {@code ServerSocket} instance bound to the nominated
78     * port on the localhost. The number of pending connections that may be
79     * backlogged is specified by {@code backlog}. If {@code aport} is 0 a free
80     * port is assigned to the socket.
81     *
82     * @param aport
83     *            the port number to listen for connection requests on.
84     * @param backlog
85     *            the number of pending connection requests, before requests
86     *            will be rejected.
87     * @throws IOException
88     *             if an error occurs while creating the server socket.
89     */
90    public ServerSocket(int aport, int backlog) throws IOException {
91        this(aport, backlog, Inet4Address.ANY);
92    }
93
94    /**
95     * Constructs a new {@code ServerSocket} instance bound to the nominated
96     * local host address and port. The number of pending connections that may
97     * be backlogged is specified by {@code backlog}. If {@code aport} is 0 a
98     * free port is assigned to the socket.
99     *
100     * @param aport
101     *            the port number to listen for connection requests on.
102     * @param localAddr
103     *            the local machine address to bind on.
104     * @param backlog
105     *            the number of pending connection requests, before requests
106     *            will be rejected.
107     * @throws IOException
108     *             if an error occurs while creating the server socket.
109     */
110    public ServerSocket(int aport, int backlog, InetAddress localAddr) throws IOException {
111        checkListen(aport);
112        impl = factory != null ? factory.createSocketImpl()
113                : new PlainServerSocketImpl();
114        InetAddress addr = localAddr == null ? Inet4Address.ANY : localAddr;
115
116        synchronized (this) {
117            impl.create(true);
118            isCreated = true;
119            try {
120                impl.bind(addr, aport);
121                isBound = true;
122                impl.listen(backlog > 0 ? backlog : defaultBacklog());
123            } catch (IOException e) {
124                close();
125                throw e;
126            }
127        }
128    }
129
130    /**
131     * Waits for an incoming request and blocks until the connection is opened.
132     * This method returns a socket object representing the just opened
133     * connection.
134     *
135     * @return the connection representing socket.
136     * @throws IOException
137     *             if an error occurs while accepting a new connection.
138     */
139    public Socket accept() throws IOException {
140        checkClosedAndCreate(false);
141        if (!isBound()) {
142            throw new SocketException("Socket is not bound");
143        }
144
145        Socket aSocket = new Socket();
146        try {
147            implAccept(aSocket);
148        } catch (IOException e) {
149            aSocket.close();
150            throw e;
151        }
152        return aSocket;
153    }
154
155    private void checkListen(int aPort) {
156        if (aPort < 0 || aPort > 65535) {
157            throw new IllegalArgumentException("Port out of range: " + aPort);
158        }
159    }
160
161    /**
162     * Closes this server socket and its implementation. Any attempt to connect
163     * to this socket thereafter will fail.
164     *
165     * @throws IOException
166     *             if an error occurs while closing this socket.
167     */
168    public void close() throws IOException {
169        isClosed = true;
170        impl.close();
171    }
172
173    /**
174     * Returns the default number of pending connections on a server socket. If
175     * the backlog value maximum is reached, any subsequent incoming request is
176     * rejected.
177     *
178     * @return int the default number of pending connection requests
179     */
180    static int defaultBacklog() {
181        return 50;
182    }
183
184    /**
185     * Gets the local IP address of this server socket or {@code null} if the
186     * socket is unbound. This is useful for multihomed hosts.
187     *
188     * @return the local address of this server socket.
189     */
190    public InetAddress getInetAddress() {
191        if (!isBound()) {
192            return null;
193        }
194        return impl.getInetAddress();
195    }
196
197    /**
198     * Gets the local port of this server socket or {@code -1} if the socket is
199     * unbound.
200     *
201     * @return the local port this server is listening on.
202     */
203    public int getLocalPort() {
204        if (!isBound()) {
205            return -1;
206        }
207        return impl.getLocalPort();
208    }
209
210    /**
211     * Gets the socket {@link SocketOptions#SO_TIMEOUT accept timeout}.
212     *
213     * @throws IOException
214     *             if the option cannot be retrieved.
215     */
216    public synchronized int getSoTimeout() throws IOException {
217        if (!isCreated) {
218            synchronized (this) {
219                if (!isCreated) {
220                    try {
221                        impl.create(true);
222                    } catch (SocketException e) {
223                        throw e;
224                    } catch (IOException e) {
225                        throw new SocketException(e.toString());
226                    }
227                    isCreated = true;
228                }
229            }
230        }
231        return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue();
232    }
233
234    /**
235     * Invokes the server socket implementation to accept a connection on the
236     * given socket {@code aSocket}.
237     *
238     * @param aSocket
239     *            the concrete {@code SocketImpl} to accept the connection
240     *            request on.
241     * @throws IOException
242     *             if the connection cannot be accepted.
243     */
244    protected final void implAccept(Socket aSocket) throws IOException {
245        synchronized (this) {
246            impl.accept(aSocket.impl);
247            aSocket.accepted();
248        }
249    }
250
251    /**
252     * Sets the server socket implementation factory of this instance. This
253     * method may only be invoked with sufficient security privilege and only
254     * once during the application lifetime.
255     *
256     * @param aFactory
257     *            the streaming socket factory to be used for further socket
258     *            instantiations.
259     * @throws IOException
260     *             if the factory could not be set or is already set.
261     */
262    public static synchronized void setSocketFactory(SocketImplFactory aFactory)
263            throws IOException {
264        if (factory != null) {
265            throw new SocketException("Factory already set");
266        }
267        factory = aFactory;
268    }
269
270    /**
271     * Sets the {@link SocketOptions#SO_TIMEOUT accept timeout} in milliseconds for this socket.
272     * This accept timeout defines the period the socket will block waiting to
273     * accept a connection before throwing an {@code InterruptedIOException}. The value
274     * {@code 0} (default) is used to set an infinite timeout. To have effect
275     * this option must be set before the blocking method was called.
276     *
277     * @param timeout the timeout in milliseconds or 0 for no timeout.
278     * @throws SocketException
279     *             if an error occurs while setting the option.
280     */
281    public synchronized void setSoTimeout(int timeout) throws SocketException {
282        checkClosedAndCreate(true);
283        if (timeout < 0) {
284            throw new IllegalArgumentException("timeout < 0");
285        }
286        impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout));
287    }
288
289    /**
290     * Returns a textual representation of this server socket including the
291     * address, port and the state. The port field is set to {@code 0} if there
292     * is no connection to the server socket.
293     *
294     * @return the textual socket representation.
295     */
296    @Override
297    public String toString() {
298        StringBuilder result = new StringBuilder(64);
299        result.append("ServerSocket[");
300        if (!isBound()) {
301            return result.append("unbound]").toString();
302        }
303        return result.append("addr=")
304                .append(getInetAddress().getHostName()).append("/")
305                .append(getInetAddress().getHostAddress()).append(
306                        ",port=0,localport=")
307                .append(getLocalPort()).append("]")
308                .toString();
309    }
310
311    /**
312     * Binds this server socket to the given local socket address with a maximum
313     * backlog of 50 unaccepted connections. If the {@code localAddr} is set to
314     * {@code null} the socket will be bound to an available local address on
315     * any free port of the system.
316     *
317     * @param localAddr
318     *            the local address and port to bind on.
319     * @throws IllegalArgumentException
320     *             if the {@code SocketAddress} is not supported.
321     * @throws IOException
322     *             if the socket is already bound or a problem occurs during
323     *             binding.
324     */
325    public void bind(SocketAddress localAddr) throws IOException {
326        bind(localAddr, defaultBacklog());
327    }
328
329    /**
330     * Binds this server socket to the given local socket address. If the
331     * {@code localAddr} is set to {@code null} the socket will be bound to an
332     * available local address on any free port of the system.
333     *
334     * @param localAddr the local machine address and port to bind on.
335     * @param backlog the maximum number of unaccepted connections. Passing 0 or
336     *     a negative value yields the default backlog of 50.
337     * @throws IllegalArgumentException if the {@code SocketAddress} is not
338     *     supported.
339     * @throws IOException if the socket is already bound or a problem occurs
340     *     during binding.
341     */
342    public void bind(SocketAddress localAddr, int backlog) throws IOException {
343        checkClosedAndCreate(true);
344        if (isBound()) {
345            throw new BindException("Socket is already bound");
346        }
347        int port = 0;
348        InetAddress addr = Inet4Address.ANY;
349        if (localAddr != null) {
350            if (!(localAddr instanceof InetSocketAddress)) {
351                throw new IllegalArgumentException("Local address not an InetSocketAddress: " +
352                        localAddr.getClass());
353            }
354            InetSocketAddress inetAddr = (InetSocketAddress) localAddr;
355            if ((addr = inetAddr.getAddress()) == null) {
356                throw new SocketException("Host is unresolved: " + inetAddr.getHostName());
357            }
358            port = inetAddr.getPort();
359        }
360
361        synchronized (this) {
362            try {
363                impl.bind(addr, port);
364                isBound = true;
365                impl.listen(backlog > 0 ? backlog : defaultBacklog());
366            } catch (IOException e) {
367                close();
368                throw e;
369            }
370        }
371    }
372
373    /**
374     * Gets the local socket address of this server socket or {@code null} if
375     * the socket is unbound. This is useful on multihomed hosts.
376     *
377     * @return the local socket address and port this socket is bound to.
378     */
379    public SocketAddress getLocalSocketAddress() {
380        if (!isBound()) {
381            return null;
382        }
383        return new InetSocketAddress(getInetAddress(), getLocalPort());
384    }
385
386    /**
387     * Returns whether this server socket is bound to a local address and port
388     * or not.
389     *
390     * @return {@code true} if this socket is bound, {@code false} otherwise.
391     */
392    public boolean isBound() {
393        return isBound;
394    }
395
396    /**
397     * Returns whether this server socket is closed or not.
398     *
399     * @return {@code true} if this socket is closed, {@code false} otherwise.
400     */
401    public boolean isClosed() {
402        return isClosed;
403    }
404
405    /**
406     * Checks whether the socket is closed, and throws an exception.
407     */
408    private void checkClosedAndCreate(boolean create) throws SocketException {
409        if (isClosed()) {
410            throw new SocketException("Socket is closed");
411        }
412
413        if (!create || isCreated) {
414            return;
415        }
416
417        synchronized (this) {
418            if (isCreated) {
419                return;
420            }
421            try {
422                impl.create(true);
423            } catch (SocketException e) {
424                throw e;
425            } catch (IOException e) {
426                throw new SocketException(e.toString());
427            }
428            isCreated = true;
429        }
430    }
431
432    /**
433     * Sets the value for the socket option {@code SocketOptions.SO_REUSEADDR}.
434     *
435     * @param reuse
436     *            the socket option setting.
437     * @throws SocketException
438     *             if an error occurs while setting the option value.
439     */
440    public void setReuseAddress(boolean reuse) throws SocketException {
441        checkClosedAndCreate(true);
442        impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse));
443    }
444
445    /**
446     * Gets the value of the socket option {@code SocketOptions.SO_REUSEADDR}.
447     *
448     * @return {@code true} if the option is enabled, {@code false} otherwise.
449     * @throws SocketException
450     *             if an error occurs while reading the option value.
451     */
452    public boolean getReuseAddress() throws SocketException {
453        checkClosedAndCreate(true);
454        return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR))
455                .booleanValue();
456    }
457
458    /**
459     * Sets this socket's {@link SocketOptions#SO_SNDBUF receive buffer size}.
460     */
461    public void setReceiveBufferSize(int size) throws SocketException {
462        checkClosedAndCreate(true);
463        if (size < 1) {
464            throw new IllegalArgumentException("size < 1");
465        }
466        impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
467    }
468
469    /**
470     * Returns this socket's {@link SocketOptions#SO_RCVBUF receive buffer size}.
471     */
472    public int getReceiveBufferSize() throws SocketException {
473        checkClosedAndCreate(true);
474        return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue();
475    }
476
477    /**
478     * Returns this socket's {@code ServerSocketChannel}, if one exists. A channel is
479     * available only if this socket wraps a channel. (That is, you can go from a
480     * channel to a socket and back again, but you can't go from an arbitrary socket to a channel.)
481     * In practice, this means that the socket must have been created by
482     * {@link java.nio.channels.ServerSocketChannel#open}.
483     */
484    public ServerSocketChannel getChannel() {
485        return null;
486    }
487
488    /**
489     * Sets performance preferences for connection time, latency and bandwidth.
490     * <p>
491     * This method does currently nothing.
492     *
493     * @param connectionTime
494     *            the value representing the importance of a short connecting
495     *            time.
496     * @param latency
497     *            the value representing the importance of low latency.
498     * @param bandwidth
499     *            the value representing the importance of high bandwidth.
500     */
501    public void setPerformancePreferences(int connectionTime, int latency,
502            int bandwidth) {
503        // Our socket implementation only provide one protocol: TCP/IP, so
504        // we do nothing for this method
505    }
506}
507