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.Closeable; 21import java.io.FileDescriptor; 22import java.io.IOException; 23import java.io.InputStream; 24import java.io.OutputStream; 25import java.nio.channels.SocketChannel; 26import libcore.io.IoBridge; 27 28/** 29 * Provides a client-side TCP socket. 30 */ 31public class Socket implements Closeable { 32 private static SocketImplFactory factory; 33 34 final SocketImpl impl; 35 private final Proxy proxy; 36 37 volatile boolean isCreated = false; 38 private boolean isBound = false; 39 private boolean isConnected = false; 40 private boolean isClosed = false; 41 private boolean isInputShutdown = false; 42 private boolean isOutputShutdown = false; 43 44 private InetAddress localAddress = Inet4Address.ANY; 45 46 private final Object connectLock = new Object(); 47 48 /** 49 * Creates a new unconnected socket. When a SocketImplFactory is defined it 50 * creates the internal socket implementation, otherwise the default socket 51 * implementation will be used for this socket. 52 * 53 * @see SocketImplFactory 54 * @see SocketImpl 55 */ 56 public Socket() { 57 this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl(); 58 this.proxy = null; 59 } 60 61 /** 62 * Creates a new unconnected socket using the given proxy type. When a 63 * {@code SocketImplFactory} is defined it creates the internal socket 64 * implementation, otherwise the default socket implementation will be used 65 * for this socket. 66 * <p> 67 * Example that will create a socket connection through a {@code SOCKS} 68 * proxy server: <br> 69 * {@code Socket sock = new Socket(new Proxy(Proxy.Type.SOCKS, new 70 * InetSocketAddress("test.domain.org", 2130)));} 71 * 72 * @param proxy 73 * the specified proxy for this socket. 74 * @throws IllegalArgumentException 75 * if the argument {@code proxy} is {@code null} or of an 76 * invalid type. 77 * @see SocketImplFactory 78 * @see SocketImpl 79 */ 80 public Socket(Proxy proxy) { 81 if (proxy == null || proxy.type() == Proxy.Type.HTTP) { 82 throw new IllegalArgumentException("Invalid proxy: " + proxy); 83 } 84 this.proxy = proxy; 85 this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl(proxy); 86 } 87 88 /** 89 * Tries to connect a socket to all IP addresses of the given hostname. 90 * 91 * @param dstName 92 * the target host name or IP address to connect to. 93 * @param dstPort 94 * the port on the target host to connect to. 95 * @param localAddress 96 * the address on the local host to bind to. 97 * @param localPort 98 * the port on the local host to bind to. 99 * @param streaming 100 * if {@code true} a streaming socket is returned, a datagram 101 * socket otherwise. 102 * @throws UnknownHostException 103 * if the host name could not be resolved into an IP address. 104 * @throws IOException 105 * if an error occurs while creating the socket. 106 */ 107 private void tryAllAddresses(String dstName, int dstPort, InetAddress 108 localAddress, int localPort, boolean streaming) throws IOException { 109 InetAddress[] dstAddresses = InetAddress.getAllByName(dstName); 110 // Loop through all the destination addresses except the last, trying to 111 // connect to each one and ignoring errors. There must be at least one 112 // address, or getAllByName would have thrown UnknownHostException. 113 InetAddress dstAddress; 114 for (int i = 0; i < dstAddresses.length - 1; i++) { 115 dstAddress = dstAddresses[i]; 116 try { 117 checkDestination(dstAddress, dstPort); 118 startupSocket(dstAddress, dstPort, localAddress, localPort, streaming); 119 return; 120 } catch (IOException ex) { 121 } 122 } 123 124 // Now try to connect to the last address in the array, handing back to 125 // the caller any exceptions that are thrown. 126 dstAddress = dstAddresses[dstAddresses.length - 1]; 127 checkDestination(dstAddress, dstPort); 128 startupSocket(dstAddress, dstPort, localAddress, localPort, streaming); 129 } 130 131 /** 132 * Creates a new streaming socket connected to the target host specified by 133 * the parameters {@code dstName} and {@code dstPort}. The socket is bound 134 * to any available port on the local host. 135 * 136 * <p>This implementation tries each IP address for the given hostname (in 137 * <a href="http://www.ietf.org/rfc/rfc3484.txt">RFC 3484</a> order) 138 * until it either connects successfully or it exhausts the set. 139 * 140 * @param dstName 141 * the target host name or IP address to connect to. 142 * @param dstPort 143 * the port on the target host to connect to. 144 * @throws UnknownHostException 145 * if the host name could not be resolved into an IP address. 146 * @throws IOException 147 * if an error occurs while creating the socket. 148 */ 149 public Socket(String dstName, int dstPort) throws UnknownHostException, IOException { 150 this(dstName, dstPort, null, 0); 151 } 152 153 /** 154 * Creates a new streaming socket connected to the target host specified by 155 * the parameters {@code dstName} and {@code dstPort}. On the local endpoint 156 * the socket is bound to the given address {@code localAddress} on port 157 * {@code localPort}. If {@code host} is {@code null} a loopback address is used to connect to. 158 * 159 * <p>This implementation tries each IP address for the given hostname (in 160 * <a href="http://www.ietf.org/rfc/rfc3484.txt">RFC 3484</a> order) 161 * until it either connects successfully or it exhausts the set. 162 * 163 * @param dstName 164 * the target host name or IP address to connect to. 165 * @param dstPort 166 * the port on the target host to connect to. 167 * @param localAddress 168 * the address on the local host to bind to. 169 * @param localPort 170 * the port on the local host to bind to. 171 * @throws UnknownHostException 172 * if the host name could not be resolved into an IP address. 173 * @throws IOException 174 * if an error occurs while creating the socket. 175 */ 176 public Socket(String dstName, int dstPort, InetAddress localAddress, int localPort) throws IOException { 177 this(); 178 tryAllAddresses(dstName, dstPort, localAddress, localPort, true); 179 } 180 181 /** 182 * Creates a new streaming or datagram socket connected to the target host 183 * specified by the parameters {@code hostName} and {@code port}. The socket 184 * is bound to any available port on the local host. 185 * 186 * <p>This implementation tries each IP address for the given hostname (in 187 * <a href="http://www.ietf.org/rfc/rfc3484.txt">RFC 3484</a> order) 188 * until it either connects successfully or it exhausts the set. 189 * 190 * @param hostName 191 * the target host name or IP address to connect to. 192 * @param port 193 * the port on the target host to connect to. 194 * @param streaming 195 * if {@code true} a streaming socket is returned, a datagram 196 * socket otherwise. 197 * @throws UnknownHostException 198 * if the host name could not be resolved into an IP address. 199 * @throws IOException 200 * if an error occurs while creating the socket. 201 * @deprecated Use {@code Socket(String, int)} instead of this for streaming 202 * sockets or an appropriate constructor of {@code 203 * DatagramSocket} for UDP transport. 204 */ 205 @Deprecated 206 public Socket(String hostName, int port, boolean streaming) throws IOException { 207 this(); 208 tryAllAddresses(hostName, port, null, 0, streaming); 209 } 210 211 /** 212 * Creates a new streaming socket connected to the target host specified by 213 * the parameters {@code dstAddress} and {@code dstPort}. The socket is 214 * bound to any available port on the local host. 215 * 216 * @param dstAddress 217 * the target host address to connect to. 218 * @param dstPort 219 * the port on the target host to connect to. 220 * @throws IOException 221 * if an error occurs while creating the socket. 222 */ 223 public Socket(InetAddress dstAddress, int dstPort) throws IOException { 224 this(); 225 checkDestination(dstAddress, dstPort); 226 startupSocket(dstAddress, dstPort, null, 0, true); 227 } 228 229 /** 230 * Creates a new streaming socket connected to the target host specified by 231 * the parameters {@code dstAddress} and {@code dstPort}. On the local 232 * endpoint the socket is bound to the given address {@code localAddress} on 233 * port {@code localPort}. 234 * 235 * @param dstAddress 236 * the target host address to connect to. 237 * @param dstPort 238 * the port on the target host to connect to. 239 * @param localAddress 240 * the address on the local host to bind to. 241 * @param localPort 242 * the port on the local host to bind to. 243 * @throws IOException 244 * if an error occurs while creating the socket. 245 */ 246 public Socket(InetAddress dstAddress, int dstPort, 247 InetAddress localAddress, int localPort) throws IOException { 248 this(); 249 checkDestination(dstAddress, dstPort); 250 startupSocket(dstAddress, dstPort, localAddress, localPort, true); 251 } 252 253 /** 254 * Creates a new streaming or datagram socket connected to the target host 255 * specified by the parameters {@code addr} and {@code port}. The socket is 256 * bound to any available port on the local host. 257 * 258 * @param addr 259 * the Internet address to connect to. 260 * @param port 261 * the port on the target host to connect to. 262 * @param streaming 263 * if {@code true} a streaming socket is returned, a datagram 264 * socket otherwise. 265 * @throws IOException 266 * if an error occurs while creating the socket. 267 * @deprecated Use {@code Socket(InetAddress, int)} instead of this for 268 * streaming sockets or an appropriate constructor of {@code 269 * DatagramSocket} for UDP transport. 270 */ 271 @Deprecated 272 public Socket(InetAddress addr, int port, boolean streaming) throws IOException { 273 this(); 274 checkDestination(addr, port); 275 startupSocket(addr, port, null, 0, streaming); 276 } 277 278 /** 279 * Creates an unconnected socket with the given socket implementation. 280 * 281 * @param impl 282 * the socket implementation to be used. 283 * @throws SocketException 284 * if an error occurs while creating the socket. 285 */ 286 protected Socket(SocketImpl impl) throws SocketException { 287 this.impl = impl; 288 this.proxy = null; 289 } 290 291 /** 292 * Checks whether the connection destination satisfies the security policy 293 * and the validity of the port range. 294 * 295 * @param destAddr 296 * the destination host address. 297 * @param dstPort 298 * the port on the destination host. 299 */ 300 private void checkDestination(InetAddress destAddr, int dstPort) { 301 if (dstPort < 0 || dstPort > 65535) { 302 throw new IllegalArgumentException("Port out of range: " + dstPort); 303 } 304 } 305 306 /** 307 * Closes the socket. It is not possible to reconnect or rebind to this 308 * socket thereafter which means a new socket instance has to be created. 309 * 310 * @throws IOException 311 * if an error occurs while closing the socket. 312 */ 313 public synchronized void close() throws IOException { 314 isClosed = true; 315 // RI compatibility: the RI returns the any address (but the original local port) after close. 316 localAddress = Inet4Address.ANY; 317 impl.close(); 318 } 319 320 /** 321 * Returns the IP address of the target host this socket is connected to, or null if this 322 * socket is not yet connected. 323 */ 324 public InetAddress getInetAddress() { 325 if (!isConnected()) { 326 return null; 327 } 328 return impl.getInetAddress(); 329 } 330 331 /** 332 * Returns an input stream to read data from this socket. 333 * 334 * @return the byte-oriented input stream. 335 * @throws IOException 336 * if an error occurs while creating the input stream or the 337 * socket is in an invalid state. 338 */ 339 public InputStream getInputStream() throws IOException { 340 checkOpenAndCreate(false); 341 if (isInputShutdown()) { 342 throw new SocketException("Socket input is shutdown"); 343 } 344 return impl.getInputStream(); 345 } 346 347 /** 348 * Returns this socket's {@link SocketOptions#SO_KEEPALIVE} setting. 349 */ 350 public boolean getKeepAlive() throws SocketException { 351 checkOpenAndCreate(true); 352 return (Boolean) impl.getOption(SocketOptions.SO_KEEPALIVE); 353 } 354 355 /** 356 * Returns the local IP address this socket is bound to, or {@code InetAddress.ANY} if 357 * the socket is unbound. 358 */ 359 public InetAddress getLocalAddress() { 360 return localAddress; 361 } 362 363 /** 364 * Returns the local port this socket is bound to, or -1 if the socket is unbound. 365 */ 366 public int getLocalPort() { 367 if (!isBound()) { 368 return -1; 369 } 370 return impl.getLocalPort(); 371 } 372 373 /** 374 * Returns an output stream to write data into this socket. 375 * 376 * @return the byte-oriented output stream. 377 * @throws IOException 378 * if an error occurs while creating the output stream or the 379 * socket is in an invalid state. 380 */ 381 public OutputStream getOutputStream() throws IOException { 382 checkOpenAndCreate(false); 383 if (isOutputShutdown()) { 384 throw new SocketException("Socket output is shutdown"); 385 } 386 return impl.getOutputStream(); 387 } 388 389 /** 390 * Returns the port number of the target host this socket is connected to, or 0 if this socket 391 * is not yet connected. 392 */ 393 public int getPort() { 394 if (!isConnected()) { 395 return 0; 396 } 397 return impl.getPort(); 398 } 399 400 /** 401 * Returns this socket's {@link SocketOptions#SO_LINGER linger} timeout in seconds, or -1 402 * for no linger (i.e. {@code close} will return immediately). 403 */ 404 public int getSoLinger() throws SocketException { 405 checkOpenAndCreate(true); 406 // The RI explicitly guarantees this idiocy in the SocketOptions.setOption documentation. 407 Object value = impl.getOption(SocketOptions.SO_LINGER); 408 if (value instanceof Integer) { 409 return (Integer) value; 410 } else { 411 return -1; 412 } 413 } 414 415 /** 416 * Returns this socket's {@link SocketOptions#SO_RCVBUF receive buffer size}. 417 */ 418 public synchronized int getReceiveBufferSize() throws SocketException { 419 checkOpenAndCreate(true); 420 return (Integer) impl.getOption(SocketOptions.SO_RCVBUF); 421 } 422 423 /** 424 * Returns this socket's {@link SocketOptions#SO_SNDBUF send buffer size}. 425 */ 426 public synchronized int getSendBufferSize() throws SocketException { 427 checkOpenAndCreate(true); 428 return (Integer) impl.getOption(SocketOptions.SO_SNDBUF); 429 } 430 431 /** 432 * Returns this socket's {@link SocketOptions#SO_TIMEOUT receive timeout}. 433 */ 434 public synchronized int getSoTimeout() throws SocketException { 435 checkOpenAndCreate(true); 436 return (Integer) impl.getOption(SocketOptions.SO_TIMEOUT); 437 } 438 439 /** 440 * Returns this socket's {@code SocketOptions#TCP_NODELAY} setting. 441 */ 442 public boolean getTcpNoDelay() throws SocketException { 443 checkOpenAndCreate(true); 444 return (Boolean) impl.getOption(SocketOptions.TCP_NODELAY); 445 } 446 447 /** 448 * Sets this socket's {@link SocketOptions#SO_KEEPALIVE} option. 449 */ 450 public void setKeepAlive(boolean keepAlive) throws SocketException { 451 if (impl != null) { 452 checkOpenAndCreate(true); 453 impl.setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(keepAlive)); 454 } 455 } 456 457 /** 458 * Sets the internal factory for creating socket implementations. This may 459 * only be executed once during the lifetime of the application. 460 * 461 * @param fac 462 * the socket implementation factory to be set. 463 * @throws IOException 464 * if the factory has been already set. 465 */ 466 public static synchronized void setSocketImplFactory(SocketImplFactory fac) 467 throws IOException { 468 if (factory != null) { 469 throw new SocketException("Factory already set"); 470 } 471 factory = fac; 472 } 473 474 /** 475 * Sets this socket's {@link SocketOptions#SO_SNDBUF send buffer size}. 476 */ 477 public synchronized void setSendBufferSize(int size) throws SocketException { 478 checkOpenAndCreate(true); 479 if (size < 1) { 480 throw new IllegalArgumentException("size < 1"); 481 } 482 impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size)); 483 } 484 485 /** 486 * Sets this socket's {@link SocketOptions#SO_RCVBUF receive buffer size}. 487 */ 488 public synchronized void setReceiveBufferSize(int size) throws SocketException { 489 checkOpenAndCreate(true); 490 if (size < 1) { 491 throw new IllegalArgumentException("size < 1"); 492 } 493 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); 494 } 495 496 /** 497 * Sets this socket's {@link SocketOptions#SO_LINGER linger} timeout in seconds. 498 * If {@code on} is false, {@code timeout} is irrelevant. 499 */ 500 public void setSoLinger(boolean on, int timeout) throws SocketException { 501 checkOpenAndCreate(true); 502 // The RI explicitly guarantees this idiocy in the SocketOptions.setOption documentation. 503 if (on && timeout < 0) { 504 throw new IllegalArgumentException("timeout < 0"); 505 } 506 if (on) { 507 impl.setOption(SocketOptions.SO_LINGER, Integer.valueOf(timeout)); 508 } else { 509 impl.setOption(SocketOptions.SO_LINGER, Boolean.FALSE); 510 } 511 } 512 513 /** 514 * Sets this socket's {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds. 515 * Use 0 for no timeout. 516 * To take effect, this option must be set before the blocking method was called. 517 */ 518 public synchronized void setSoTimeout(int timeout) throws SocketException { 519 checkOpenAndCreate(true); 520 if (timeout < 0) { 521 throw new IllegalArgumentException("timeout < 0"); 522 } 523 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout)); 524 } 525 526 /** 527 * Sets this socket's {@link SocketOptions#TCP_NODELAY} option. 528 */ 529 public void setTcpNoDelay(boolean on) throws SocketException { 530 checkOpenAndCreate(true); 531 impl.setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on)); 532 } 533 534 /** 535 * Creates a stream socket, binds it to the nominated local address/port, 536 * then connects it to the nominated destination address/port. 537 * 538 * @param dstAddress 539 * the destination host address. 540 * @param dstPort 541 * the port on the destination host. 542 * @param localAddress 543 * the address on the local machine to bind. 544 * @param localPort 545 * the port on the local machine to bind. 546 * @throws IOException 547 * thrown if an error occurs during the bind or connect 548 * operations. 549 */ 550 private void startupSocket(InetAddress dstAddress, int dstPort, 551 InetAddress localAddress, int localPort, boolean streaming) 552 throws IOException { 553 554 if (localPort < 0 || localPort > 65535) { 555 throw new IllegalArgumentException("Local port out of range: " + localPort); 556 } 557 558 InetAddress addr = localAddress == null ? Inet4Address.ANY : localAddress; 559 synchronized (this) { 560 impl.create(streaming); 561 isCreated = true; 562 try { 563 if (!streaming || !usingSocks()) { 564 impl.bind(addr, localPort); 565 } 566 isBound = true; 567 impl.connect(dstAddress, dstPort); 568 isConnected = true; 569 cacheLocalAddress(); 570 } catch (IOException e) { 571 impl.close(); 572 throw e; 573 } 574 } 575 } 576 577 private boolean usingSocks() { 578 return proxy != null && proxy.type() == Proxy.Type.SOCKS; 579 } 580 581 /** 582 * Returns a {@code String} containing a concise, human-readable description of the 583 * socket. 584 * 585 * @return the textual representation of this socket. 586 */ 587 @Override 588 public String toString() { 589 if (!isConnected()) { 590 return "Socket[unconnected]"; 591 } 592 return impl.toString(); 593 } 594 595 /** 596 * Closes the input stream of this socket. Any further data sent to this 597 * socket will be discarded. Reading from this socket after this method has 598 * been called will return the value {@code EOF}. 599 * 600 * @throws IOException 601 * if an error occurs while closing the socket input stream. 602 * @throws SocketException 603 * if the input stream is already closed. 604 */ 605 public void shutdownInput() throws IOException { 606 if (isInputShutdown()) { 607 throw new SocketException("Socket input is shutdown"); 608 } 609 checkOpenAndCreate(false); 610 impl.shutdownInput(); 611 isInputShutdown = true; 612 } 613 614 /** 615 * Closes the output stream of this socket. All buffered data will be sent 616 * followed by the termination sequence. Writing to the closed output stream 617 * will cause an {@code IOException}. 618 * 619 * @throws IOException 620 * if an error occurs while closing the socket output stream. 621 * @throws SocketException 622 * if the output stream is already closed. 623 */ 624 public void shutdownOutput() throws IOException { 625 if (isOutputShutdown()) { 626 throw new SocketException("Socket output is shutdown"); 627 } 628 checkOpenAndCreate(false); 629 impl.shutdownOutput(); 630 isOutputShutdown = true; 631 } 632 633 /** 634 * Checks whether the socket is closed, and throws an exception. Otherwise 635 * creates the underlying SocketImpl. 636 * 637 * @throws SocketException 638 * if the socket is closed. 639 */ 640 private void checkOpenAndCreate(boolean create) throws SocketException { 641 if (isClosed()) { 642 throw new SocketException("Socket is closed"); 643 } 644 if (!create) { 645 if (!isConnected()) { 646 throw new SocketException("Socket is not connected"); 647 // a connected socket must be created 648 } 649 650 /* 651 * return directly to fix a possible bug, if !create, should return 652 * here 653 */ 654 return; 655 } 656 if (isCreated) { 657 return; 658 } 659 synchronized (this) { 660 if (isCreated) { 661 return; 662 } 663 try { 664 impl.create(true); 665 } catch (SocketException e) { 666 throw e; 667 } catch (IOException e) { 668 throw new SocketException(e.toString()); 669 } 670 isCreated = true; 671 } 672 } 673 674 /** 675 * Returns the local address and port of this socket as a SocketAddress or 676 * null if the socket is unbound. This is useful on multihomed 677 * hosts. 678 */ 679 public SocketAddress getLocalSocketAddress() { 680 if (!isBound()) { 681 return null; 682 } 683 return new InetSocketAddress(getLocalAddress(), getLocalPort()); 684 } 685 686 /** 687 * Returns the remote address and port of this socket as a {@code 688 * SocketAddress} or null if the socket is not connected. 689 * 690 * @return the remote socket address and port. 691 */ 692 public SocketAddress getRemoteSocketAddress() { 693 if (!isConnected()) { 694 return null; 695 } 696 return new InetSocketAddress(getInetAddress(), getPort()); 697 } 698 699 /** 700 * Returns whether this socket is bound to a local address and port. 701 * 702 * @return {@code true} if the socket is bound to a local address, {@code 703 * false} otherwise. 704 */ 705 public boolean isBound() { 706 return isBound; 707 } 708 709 /** 710 * Returns whether this socket is connected to a remote host. 711 * 712 * @return {@code true} if the socket is connected, {@code false} otherwise. 713 */ 714 public boolean isConnected() { 715 return isConnected; 716 } 717 718 /** 719 * Returns whether this socket is closed. 720 * 721 * @return {@code true} if the socket is closed, {@code false} otherwise. 722 */ 723 public boolean isClosed() { 724 return isClosed; 725 } 726 727 /** 728 * Binds this socket to the given local host address and port specified by 729 * the SocketAddress {@code localAddr}. If {@code localAddr} is set to 730 * {@code null}, this socket will be bound to an available local address on 731 * any free port. 732 * 733 * @param localAddr 734 * the specific address and port on the local machine to bind to. 735 * @throws IllegalArgumentException 736 * if the given SocketAddress is invalid or not supported. 737 * @throws IOException 738 * if the socket is already bound or an error occurs while 739 * binding. 740 */ 741 public void bind(SocketAddress localAddr) throws IOException { 742 checkOpenAndCreate(true); 743 if (isBound()) { 744 throw new BindException("Socket is already bound"); 745 } 746 747 int port = 0; 748 InetAddress addr = Inet4Address.ANY; 749 if (localAddr != null) { 750 if (!(localAddr instanceof InetSocketAddress)) { 751 throw new IllegalArgumentException("Local address not an InetSocketAddress: " + 752 localAddr.getClass()); 753 } 754 InetSocketAddress inetAddr = (InetSocketAddress) localAddr; 755 if ((addr = inetAddr.getAddress()) == null) { 756 throw new UnknownHostException("Host is unresolved: " + inetAddr.getHostName()); 757 } 758 port = inetAddr.getPort(); 759 } 760 761 synchronized (this) { 762 try { 763 impl.bind(addr, port); 764 isBound = true; 765 cacheLocalAddress(); 766 } catch (IOException e) { 767 impl.close(); 768 throw e; 769 } 770 } 771 } 772 773 /** 774 * Connects this socket to the given remote host address and port specified 775 * by the SocketAddress {@code remoteAddr}. 776 * 777 * @param remoteAddr 778 * the address and port of the remote host to connect to. 779 * @throws IllegalArgumentException 780 * if the given SocketAddress is invalid or not supported. 781 * @throws IOException 782 * if the socket is already connected or an error occurs while 783 * connecting. 784 */ 785 public void connect(SocketAddress remoteAddr) throws IOException { 786 connect(remoteAddr, 0); 787 } 788 789 /** 790 * Connects this socket to the given remote host address and port specified 791 * by the SocketAddress {@code remoteAddr} with the specified timeout. The 792 * connecting method will block until the connection is established or an 793 * error occurred. 794 * 795 * @param remoteAddr 796 * the address and port of the remote host to connect to. 797 * @param timeout 798 * the timeout value in milliseconds or {@code 0} for an infinite 799 * timeout. 800 * @throws IllegalArgumentException 801 * if the given SocketAddress is invalid or not supported or the 802 * timeout value is negative. 803 * @throws IOException 804 * if the socket is already connected or an error occurs while 805 * connecting. 806 */ 807 public void connect(SocketAddress remoteAddr, int timeout) throws IOException { 808 checkOpenAndCreate(true); 809 if (timeout < 0) { 810 throw new IllegalArgumentException("timeout < 0"); 811 } 812 if (isConnected()) { 813 throw new SocketException("Already connected"); 814 } 815 if (remoteAddr == null) { 816 throw new IllegalArgumentException("remoteAddr == null"); 817 } 818 819 if (!(remoteAddr instanceof InetSocketAddress)) { 820 throw new IllegalArgumentException("Remote address not an InetSocketAddress: " + 821 remoteAddr.getClass()); 822 } 823 InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr; 824 InetAddress addr; 825 if ((addr = inetAddr.getAddress()) == null) { 826 throw new UnknownHostException("Host is unresolved: " + inetAddr.getHostName()); 827 } 828 int port = inetAddr.getPort(); 829 830 checkDestination(addr, port); 831 synchronized (connectLock) { 832 try { 833 if (!isBound()) { 834 // socket already created at this point by earlier call or 835 // checkOpenAndCreate this caused us to lose socket 836 // options on create 837 // impl.create(true); 838 if (!usingSocks()) { 839 impl.bind(Inet4Address.ANY, 0); 840 } 841 isBound = true; 842 } 843 impl.connect(remoteAddr, timeout); 844 isConnected = true; 845 cacheLocalAddress(); 846 } catch (IOException e) { 847 impl.close(); 848 throw e; 849 } 850 } 851 } 852 853 /** 854 * Returns whether the incoming channel of the socket has already been 855 * closed. 856 * 857 * @return {@code true} if reading from this socket is not possible anymore, 858 * {@code false} otherwise. 859 */ 860 public boolean isInputShutdown() { 861 return isInputShutdown; 862 } 863 864 /** 865 * Returns whether the outgoing channel of the socket has already been 866 * closed. 867 * 868 * @return {@code true} if writing to this socket is not possible anymore, 869 * {@code false} otherwise. 870 */ 871 public boolean isOutputShutdown() { 872 return isOutputShutdown; 873 } 874 875 /** 876 * Sets this socket's {@link SocketOptions#SO_REUSEADDR} option. 877 */ 878 public void setReuseAddress(boolean reuse) throws SocketException { 879 checkOpenAndCreate(true); 880 impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse)); 881 } 882 883 /** 884 * Returns this socket's {@link SocketOptions#SO_REUSEADDR} setting. 885 */ 886 public boolean getReuseAddress() throws SocketException { 887 checkOpenAndCreate(true); 888 return (Boolean) impl.getOption(SocketOptions.SO_REUSEADDR); 889 } 890 891 /** 892 * Sets this socket's {@link SocketOptions#SO_OOBINLINE} option. 893 */ 894 public void setOOBInline(boolean oobinline) throws SocketException { 895 checkOpenAndCreate(true); 896 impl.setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(oobinline)); 897 } 898 899 /** 900 * Returns this socket's {@link SocketOptions#SO_OOBINLINE} setting. 901 */ 902 public boolean getOOBInline() throws SocketException { 903 checkOpenAndCreate(true); 904 return (Boolean) impl.getOption(SocketOptions.SO_OOBINLINE); 905 } 906 907 /** 908 * Sets this socket's {@link SocketOptions#IP_TOS} value for every packet sent by this socket. 909 */ 910 public void setTrafficClass(int value) throws SocketException { 911 checkOpenAndCreate(true); 912 if (value < 0 || value > 255) { 913 throw new IllegalArgumentException("Value doesn't fit in an unsigned byte: " + value); 914 } 915 impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value)); 916 } 917 918 /** 919 * Returns this socket's {@see SocketOptions#IP_TOS} setting. 920 */ 921 public int getTrafficClass() throws SocketException { 922 checkOpenAndCreate(true); 923 return (Integer) impl.getOption(SocketOptions.IP_TOS); 924 } 925 926 /** 927 * Sends the given single byte data which is represented by the lowest octet 928 * of {@code value} as "TCP urgent data". 929 * 930 * @param value 931 * the byte of urgent data to be sent. 932 * @throws IOException 933 * if an error occurs while sending urgent data. 934 */ 935 public void sendUrgentData(int value) throws IOException { 936 impl.sendUrgentData(value); 937 } 938 939 /** 940 * Set the appropriate flags for a socket created by {@code 941 * ServerSocket.accept()}. 942 * 943 * @see ServerSocket#implAccept 944 */ 945 void accepted() throws SocketException { 946 isCreated = isBound = isConnected = true; 947 cacheLocalAddress(); 948 } 949 950 private void cacheLocalAddress() throws SocketException { 951 this.localAddress = IoBridge.getSocketLocalAddress(impl.fd); 952 } 953 954 /** 955 * Returns this socket's {@code SocketChannel}, if one exists. A channel is 956 * available only if this socket wraps a channel. (That is, you can go from a 957 * channel to a socket and back again, but you can't go from an arbitrary socket to a channel.) 958 * In practice, this means that the socket must have been created by 959 * {@link java.nio.channels.ServerSocketChannel#accept} or 960 * {@link java.nio.channels.SocketChannel#open}. 961 */ 962 public SocketChannel getChannel() { 963 return null; 964 } 965 966 /** 967 * @hide internal use only 968 */ 969 public FileDescriptor getFileDescriptor$() { 970 return impl.fd; 971 } 972 973 /** 974 * Sets performance preferences for connectionTime, latency and bandwidth. 975 * 976 * <p>This method does currently nothing. 977 * 978 * @param connectionTime 979 * the value representing the importance of a short connecting 980 * time. 981 * @param latency 982 * the value representing the importance of low latency. 983 * @param bandwidth 984 * the value representing the importance of high bandwidth. 985 */ 986 public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { 987 // Our socket implementation only provide one protocol: TCP/IP, so 988 // we do nothing for this method 989 } 990} 991