• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 package java.net;
19 
20 import java.io.Closeable;
21 import java.io.IOException;
22 import java.nio.channels.ServerSocketChannel;
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  */
30 public class ServerSocket implements Closeable {
31     /**
32      * The RI specifies that where the caller doesn't give an explicit backlog,
33      * the default is 50. The OS disagrees, so we need to explicitly call listen(2).
34      */
35     private static final int DEFAULT_BACKLOG = 50;
36 
37     private final SocketImpl impl;
38 
39     /**
40      * @hide internal use only
41      */
getImpl$()42     public SocketImpl getImpl$() {
43         return impl;
44     }
45 
46     static SocketImplFactory factory;
47 
48     private boolean isBound;
49 
50     private boolean isClosed;
51 
52     /**
53      * Constructs a new unbound {@code ServerSocket}.
54      *
55      * @throws IOException if an error occurs while creating the socket.
56      */
ServerSocket()57     public ServerSocket() throws IOException {
58         this.impl = factory != null ? factory.createSocketImpl()
59                 : new PlainServerSocketImpl();
60         impl.create(true);
61     }
62 
63     /**
64      * Constructs a new {@code ServerSocket} instance bound to the given {@code port}.
65      * The backlog is set to 50. If {@code port == 0}, a port will be assigned by the OS.
66      *
67      * @throws IOException if an error occurs while creating the socket.
68      */
ServerSocket(int port)69     public ServerSocket(int port) throws IOException {
70         this(port, DEFAULT_BACKLOG, Inet4Address.ANY);
71     }
72 
73     /**
74      * Constructs a new {@code ServerSocket} instance bound to the given {@code port}.
75      * The backlog is set to {@code backlog}.
76      * If {@code port == 0}, a port will be assigned by the OS.
77      *
78      * @throws IOException if an error occurs while creating the socket.
79      */
ServerSocket(int port, int backlog)80     public ServerSocket(int port, int backlog) throws IOException {
81         this(port, backlog, Inet4Address.ANY);
82     }
83 
84     /**
85      * Constructs a new {@code ServerSocket} instance bound to the given {@code localAddress}
86      * and {@code port}. The backlog is set to {@code backlog}.
87      * If {@code localAddress == null}, the ANY address is used.
88      * If {@code port == 0}, a port will be assigned by the OS.
89      *
90      * @throws IOException if an error occurs while creating the socket.
91      */
ServerSocket(int port, int backlog, InetAddress localAddress)92     public ServerSocket(int port, int backlog, InetAddress localAddress) throws IOException {
93         checkListen(port);
94         this.impl = factory != null ? factory.createSocketImpl()
95                 : new PlainServerSocketImpl();
96         InetAddress addr = (localAddress == null) ? Inet4Address.ANY : localAddress;
97 
98         synchronized (this) {
99             impl.create(true);
100             try {
101                 impl.bind(addr, port);
102                 isBound = true;
103                 impl.listen(backlog > 0 ? backlog : DEFAULT_BACKLOG);
104             } catch (IOException e) {
105                 close();
106                 throw e;
107             }
108         }
109     }
110 
111     /**
112      * Waits for an incoming request and blocks until the connection is opened.
113      * This method returns a socket object representing the just opened
114      * connection.
115      *
116      * @return the connection representing socket.
117      * @throws IOException
118      *             if an error occurs while accepting a new connection.
119      */
accept()120     public Socket accept() throws IOException {
121         checkOpen();
122         if (!isBound()) {
123             throw new SocketException("Socket is not bound");
124         }
125 
126         Socket aSocket = new Socket();
127         try {
128             implAccept(aSocket);
129         } catch (IOException e) {
130             aSocket.close();
131             throw e;
132         }
133         return aSocket;
134     }
135 
checkListen(int aPort)136     private void checkListen(int aPort) {
137         if (aPort < 0 || aPort > 65535) {
138             throw new IllegalArgumentException("Port out of range: " + aPort);
139         }
140     }
141 
142     /**
143      * Closes this server socket and its implementation. Any attempt to connect
144      * to this socket thereafter will fail.
145      *
146      * @throws IOException
147      *             if an error occurs while closing this socket.
148      */
close()149     public void close() throws IOException {
150         isClosed = true;
151         impl.close();
152     }
153 
154     /**
155      * Gets the local IP address of this server socket or {@code null} if the
156      * socket is unbound. This is useful for multihomed hosts.
157      *
158      * @return the local address of this server socket.
159      */
getInetAddress()160     public InetAddress getInetAddress() {
161         if (!isBound()) {
162             return null;
163         }
164         return impl.getInetAddress();
165     }
166 
167     /**
168      * Gets the local port of this server socket or {@code -1} if the socket is
169      * unbound.
170      *
171      * @return the local port this server is listening on.
172      */
getLocalPort()173     public int getLocalPort() {
174         if (!isBound()) {
175             return -1;
176         }
177         return impl.getLocalPort();
178     }
179 
180     /**
181      * Gets the socket {@link SocketOptions#SO_TIMEOUT accept timeout}.
182      *
183      * @throws IOException
184      *             if the option cannot be retrieved.
185      */
getSoTimeout()186     public synchronized int getSoTimeout() throws IOException {
187         checkOpen();
188         return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue();
189     }
190 
191     /**
192      * Invokes the server socket implementation to accept a connection on the
193      * given socket {@code aSocket}.
194      *
195      * @param aSocket
196      *            the concrete {@code SocketImpl} to accept the connection
197      *            request on.
198      * @throws IOException
199      *             if the connection cannot be accepted.
200      */
implAccept(Socket aSocket)201     protected final void implAccept(Socket aSocket) throws IOException {
202         synchronized (this) {
203             impl.accept(aSocket.impl);
204             aSocket.accepted();
205         }
206     }
207 
208     /**
209      * Sets the server socket implementation factory of this instance. This
210      * method may only be invoked with sufficient security privilege and only
211      * once during the application lifetime.
212      *
213      * @param aFactory
214      *            the streaming socket factory to be used for further socket
215      *            instantiations.
216      * @throws IOException
217      *             if the factory could not be set or is already set.
218      */
setSocketFactory(SocketImplFactory aFactory)219     public static synchronized void setSocketFactory(SocketImplFactory aFactory) throws IOException {
220         if (factory != null) {
221             throw new SocketException("Factory already set");
222         }
223         factory = aFactory;
224     }
225 
226     /**
227      * Sets the {@link SocketOptions#SO_TIMEOUT accept timeout} in milliseconds for this socket.
228      * This accept timeout defines the period the socket will block waiting to
229      * accept a connection before throwing an {@code InterruptedIOException}. The value
230      * {@code 0} (default) is used to set an infinite timeout. To have effect
231      * this option must be set before the blocking method was called.
232      *
233      * @param timeout the timeout in milliseconds or 0 for no timeout.
234      * @throws SocketException
235      *             if an error occurs while setting the option.
236      */
setSoTimeout(int timeout)237     public synchronized void setSoTimeout(int timeout) throws SocketException {
238         checkOpen();
239         if (timeout < 0) {
240             throw new IllegalArgumentException("timeout < 0");
241         }
242         impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout));
243     }
244 
245     /**
246      * Returns a textual representation of this server socket including the
247      * address, port and the state. The port field is set to {@code 0} if there
248      * is no connection to the server socket.
249      *
250      * @return the textual socket representation.
251      */
252     @Override
toString()253     public String toString() {
254         StringBuilder result = new StringBuilder(64);
255         result.append("ServerSocket[");
256         if (!isBound()) {
257             return result.append("unbound]").toString();
258         }
259         return result.append("addr=")
260                 .append(getInetAddress().getHostName()).append("/")
261                 .append(getInetAddress().getHostAddress()).append(
262                         ",port=0,localport=")
263                 .append(getLocalPort()).append("]")
264                 .toString();
265     }
266 
267     /**
268      * Binds this server socket to the given local socket address with a maximum
269      * backlog of 50 unaccepted connections. If the {@code localAddr} is set to
270      * {@code null} the socket will be bound to an available local address on
271      * any free port of the system.
272      *
273      * @param localAddr
274      *            the local address and port to bind on.
275      * @throws IllegalArgumentException
276      *             if the {@code SocketAddress} is not supported.
277      * @throws IOException
278      *             if the socket is already bound or a problem occurs during
279      *             binding.
280      */
bind(SocketAddress localAddr)281     public void bind(SocketAddress localAddr) throws IOException {
282         bind(localAddr, DEFAULT_BACKLOG);
283     }
284 
285     /**
286      * Binds this server socket to the given local socket address. If the
287      * {@code localAddr} is set to {@code null} the socket will be bound to an
288      * available local address on any free port of the system.
289      *
290      * @param localAddr the local machine address and port to bind on.
291      * @param backlog the maximum number of unaccepted connections. Passing 0 or
292      *     a negative value yields the default backlog of 50.
293      * @throws IllegalArgumentException if the {@code SocketAddress} is not
294      *     supported.
295      * @throws IOException if the socket is already bound or a problem occurs
296      *     during binding.
297      */
bind(SocketAddress localAddr, int backlog)298     public void bind(SocketAddress localAddr, int backlog) throws IOException {
299         checkOpen();
300         if (isBound()) {
301             throw new BindException("Socket is already bound");
302         }
303         int port = 0;
304         InetAddress addr = Inet4Address.ANY;
305         if (localAddr != null) {
306             if (!(localAddr instanceof InetSocketAddress)) {
307                 throw new IllegalArgumentException("Local address not an InetSocketAddress: " +
308                         localAddr.getClass());
309             }
310             InetSocketAddress inetAddr = (InetSocketAddress) localAddr;
311             if ((addr = inetAddr.getAddress()) == null) {
312                 throw new SocketException("Host is unresolved: " + inetAddr.getHostName());
313             }
314             port = inetAddr.getPort();
315         }
316 
317         synchronized (this) {
318             try {
319                 impl.bind(addr, port);
320                 isBound = true;
321                 impl.listen(backlog > 0 ? backlog : DEFAULT_BACKLOG);
322             } catch (IOException e) {
323                 close();
324                 throw e;
325             }
326         }
327     }
328 
329     /**
330      * Gets the local socket address of this server socket or {@code null} if
331      * the socket is unbound. This is useful on multihomed hosts.
332      *
333      * @return the local socket address and port this socket is bound to.
334      */
getLocalSocketAddress()335     public SocketAddress getLocalSocketAddress() {
336         if (!isBound()) {
337             return null;
338         }
339         return new InetSocketAddress(getInetAddress(), getLocalPort());
340     }
341 
342     /**
343      * Returns whether this server socket is bound to a local address and port
344      * or not.
345      *
346      * @return {@code true} if this socket is bound, {@code false} otherwise.
347      */
isBound()348     public boolean isBound() {
349         return isBound;
350     }
351 
352     /**
353      * Returns whether this server socket is closed or not.
354      *
355      * @return {@code true} if this socket is closed, {@code false} otherwise.
356      */
isClosed()357     public boolean isClosed() {
358         return isClosed;
359     }
360 
checkOpen()361     private void checkOpen() throws SocketException {
362         if (isClosed()) {
363             throw new SocketException("Socket is closed");
364         }
365     }
366 
367     /**
368      * Sets the value for the socket option {@code SocketOptions.SO_REUSEADDR}.
369      *
370      * @param reuse
371      *            the socket option setting.
372      * @throws SocketException
373      *             if an error occurs while setting the option value.
374      */
setReuseAddress(boolean reuse)375     public void setReuseAddress(boolean reuse) throws SocketException {
376         checkOpen();
377         impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse));
378     }
379 
380     /**
381      * Gets the value of the socket option {@code SocketOptions.SO_REUSEADDR}.
382      *
383      * @return {@code true} if the option is enabled, {@code false} otherwise.
384      * @throws SocketException
385      *             if an error occurs while reading the option value.
386      */
getReuseAddress()387     public boolean getReuseAddress() throws SocketException {
388         checkOpen();
389         return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR)).booleanValue();
390     }
391 
392     /**
393      * Sets this socket's {@link SocketOptions#SO_SNDBUF receive buffer size}.
394      */
setReceiveBufferSize(int size)395     public void setReceiveBufferSize(int size) throws SocketException {
396         checkOpen();
397         if (size < 1) {
398             throw new IllegalArgumentException("size < 1");
399         }
400         impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
401     }
402 
403     /**
404      * Returns this socket's {@link SocketOptions#SO_RCVBUF receive buffer size}.
405      */
getReceiveBufferSize()406     public int getReceiveBufferSize() throws SocketException {
407         checkOpen();
408         return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue();
409     }
410 
411     /**
412      * Returns this socket's {@code ServerSocketChannel}, if one exists. A channel is
413      * available only if this socket wraps a channel. (That is, you can go from a
414      * channel to a socket and back again, but you can't go from an arbitrary socket to a channel.)
415      * In practice, this means that the socket must have been created by
416      * {@link java.nio.channels.ServerSocketChannel#open}.
417      */
getChannel()418     public ServerSocketChannel getChannel() {
419         return null;
420     }
421 
422     /**
423      * Sets performance preferences for connection time, latency and bandwidth.
424      * <p>
425      * This method does currently nothing.
426      *
427      * @param connectionTime
428      *            the value representing the importance of a short connecting
429      *            time.
430      * @param latency
431      *            the value representing the importance of low latency.
432      * @param bandwidth
433      *            the value representing the importance of high bandwidth.
434      */
setPerformancePreferences(int connectionTime, int latency, int bandwidth)435     public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
436         // Our socket implementation only provide one protocol: TCP/IP, so
437         // we do nothing for this method
438     }
439 }
440