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