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