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