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