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