PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/luni/src/main/java/java/net/Socket.java

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