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