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