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