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