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