1. /*
  2. * @(#)PlainSocketImpl.java 1.65 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.net;
  8. import java.io.IOException;
  9. import java.io.InputStream;
  10. import java.io.OutputStream;
  11. import java.io.InterruptedIOException;
  12. import java.io.FileDescriptor;
  13. import java.io.ByteArrayOutputStream;
  14. import sun.net.ConnectionResetException;
  15. /**
  16. * Default Socket Implementation. This implementation does
  17. * not implement any security checks.
  18. * Note this class should <b>NOT</b> be public.
  19. *
  20. * @author Steven B. Byrne
  21. * @version 1.65, 12/19/03
  22. */
  23. class PlainSocketImpl extends SocketImpl
  24. {
  25. /* instance variable for SO_TIMEOUT */
  26. int timeout; // timeout in millisec
  27. // traffic class
  28. private int trafficClass;
  29. private boolean shut_rd = false;
  30. private boolean shut_wr = false;
  31. private SocketInputStream socketInputStream = null;
  32. /* number of threads using the FileDescriptor */
  33. private int fdUseCount = 0;
  34. /* lock when increment/decrementing fdUseCount */
  35. private Object fdLock = new Object();
  36. /* indicates a close is pending on the file descriptor */
  37. private boolean closePending = false;
  38. /* indicates connection reset state */
  39. private int CONNECTION_NOT_RESET = 0;
  40. private int CONNECTION_RESET_PENDING = 1;
  41. private int CONNECTION_RESET = 2;
  42. private int resetState;
  43. private Object resetLock = new Object();
  44. /* second fd, used for ipv6 on windows only.
  45. * fd1 is used for listeners and for client sockets at initialization
  46. * until the socket is connected. Up to this point fd always refers
  47. * to the ipv4 socket and fd1 to the ipv6 socket. After the socket
  48. * becomes connected, fd always refers to the connected socket
  49. * (either v4 or v6) and fd1 is closed.
  50. *
  51. * For ServerSockets, fd always refers to the v4 listener and
  52. * fd1 the v6 listener.
  53. */
  54. private FileDescriptor fd1;
  55. /*
  56. * Needed for ipv6 on windows because we need to know
  57. * if the socket is bound to ::0 or 0.0.0.0, when a caller
  58. * asks for it. Otherwise we don't know which socket to ask.
  59. */
  60. private InetAddress anyLocalBoundAddr=null;
  61. /* to prevent starvation when listening on two sockets, this is
  62. * is used to hold the id of the last socket we accepted on.
  63. */
  64. private int lastfd = -1;
  65. /**
  66. * Load net library into runtime.
  67. */
  68. static {
  69. java.security.AccessController.doPrivileged(
  70. new sun.security.action.LoadLibraryAction("net"));
  71. initProto();
  72. }
  73. /**
  74. * Constructs an empty instance.
  75. */
  76. PlainSocketImpl() { }
  77. /**
  78. * Constructs an instance with the given file descriptor.
  79. * Note, this will not work with IPv6, since two fds are used.
  80. */
  81. PlainSocketImpl(FileDescriptor fd) {
  82. this.fd = fd;
  83. }
  84. /**
  85. * Creates a socket with a boolean that specifies whether this
  86. * is a stream socket (true) or an unconnected UDP socket (false).
  87. */
  88. protected synchronized void create(boolean stream) throws IOException {
  89. fd = new FileDescriptor();
  90. fd1 = new FileDescriptor();
  91. socketCreate(stream);
  92. if (socket != null)
  93. socket.setCreated();
  94. if (serverSocket != null)
  95. serverSocket.setCreated();
  96. }
  97. /**
  98. * Creates a socket and connects it to the specified port on
  99. * the specified host.
  100. * @param host the specified host
  101. * @param port the specified port
  102. */
  103. protected void connect(String host, int port)
  104. throws UnknownHostException, IOException
  105. {
  106. IOException pending = null;
  107. try {
  108. InetAddress address = InetAddress.getByName(host);
  109. try {
  110. connectToAddress(address, port, timeout);
  111. return;
  112. } catch (IOException e) {
  113. pending = e;
  114. }
  115. } catch (UnknownHostException e) {
  116. pending = e;
  117. }
  118. // everything failed
  119. close();
  120. throw pending;
  121. }
  122. /**
  123. * Creates a socket and connects it to the specified address on
  124. * the specified port.
  125. * @param address the address
  126. * @param port the specified port
  127. */
  128. protected void connect(InetAddress address, int port) throws IOException {
  129. this.port = port;
  130. this.address = address;
  131. try {
  132. connectToAddress(address, port, timeout);
  133. return;
  134. } catch (IOException e) {
  135. // everything failed
  136. close();
  137. throw e;
  138. }
  139. }
  140. /**
  141. * Creates a socket and connects it to the specified address on
  142. * the specified port.
  143. * @param address the address
  144. * @param timeout the timeout value in milliseconds, or zero for no timeout.
  145. * @throws IOException if connection fails
  146. * @throws IllegalArgumentException if address is null or is a
  147. * SocketAddress subclass not supported by this socket
  148. * @since 1.4
  149. */
  150. protected void connect(SocketAddress address, int timeout) throws IOException {
  151. if (address == null || !(address instanceof InetSocketAddress))
  152. throw new IllegalArgumentException("unsupported address type");
  153. InetSocketAddress addr = (InetSocketAddress) address;
  154. if (addr.isUnresolved())
  155. throw new UnknownHostException(addr.getHostName());
  156. this.port = addr.getPort();
  157. this.address = addr.getAddress();
  158. try {
  159. connectToAddress(this.address, port, timeout);
  160. return;
  161. } catch (IOException e) {
  162. // everything failed
  163. close();
  164. throw e;
  165. }
  166. }
  167. private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
  168. if (address.isAnyLocalAddress()) {
  169. doConnect(InetAddress.getLocalHost(), port, timeout);
  170. } else {
  171. doConnect(address, port, timeout);
  172. }
  173. }
  174. public void setOption(int opt, Object val) throws SocketException {
  175. if (isClosedOrPending()) {
  176. throw new SocketException("Socket Closed");
  177. }
  178. boolean on = true;
  179. switch (opt) {
  180. /* check type safety b4 going native. These should never
  181. * fail, since only java.Socket* has access to
  182. * PlainSocketImpl.setOption().
  183. */
  184. case SO_LINGER:
  185. if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
  186. throw new SocketException("Bad parameter for option");
  187. if (val instanceof Boolean) {
  188. /* true only if disabling - enabling should be Integer */
  189. on = false;
  190. }
  191. break;
  192. case SO_TIMEOUT:
  193. if (val == null || (!(val instanceof Integer)))
  194. throw new SocketException("Bad parameter for SO_TIMEOUT");
  195. int tmp = ((Integer) val).intValue();
  196. if (tmp < 0)
  197. throw new IllegalArgumentException("timeout < 0");
  198. timeout = tmp;
  199. break;
  200. case IP_TOS:
  201. if (val == null || !(val instanceof Integer)) {
  202. throw new SocketException("bad argument for IP_TOS");
  203. }
  204. trafficClass = ((Integer)val).intValue();
  205. break;
  206. case SO_BINDADDR:
  207. throw new SocketException("Cannot re-bind socket");
  208. case TCP_NODELAY:
  209. if (val == null || !(val instanceof Boolean))
  210. throw new SocketException("bad parameter for TCP_NODELAY");
  211. on = ((Boolean)val).booleanValue();
  212. break;
  213. case SO_SNDBUF:
  214. case SO_RCVBUF:
  215. if (val == null || !(val instanceof Integer) ||
  216. !(((Integer)val).intValue() > 0)) {
  217. throw new SocketException("bad parameter for SO_SNDBUF " +
  218. "or SO_RCVBUF");
  219. }
  220. break;
  221. case SO_KEEPALIVE:
  222. if (val == null || !(val instanceof Boolean))
  223. throw new SocketException("bad parameter for SO_KEEPALIVE");
  224. on = ((Boolean)val).booleanValue();
  225. break;
  226. case SO_OOBINLINE:
  227. if (val == null || !(val instanceof Boolean))
  228. throw new SocketException("bad parameter for SO_OOBINLINE");
  229. on = ((Boolean)val).booleanValue();
  230. break;
  231. case SO_REUSEADDR:
  232. if (val == null || !(val instanceof Boolean))
  233. throw new SocketException("bad parameter for SO_REUSEADDR");
  234. on = ((Boolean)val).booleanValue();
  235. break;
  236. default:
  237. throw new SocketException("unrecognized TCP option: " + opt);
  238. }
  239. socketSetOption(opt, on, val);
  240. }
  241. public Object getOption(int opt) throws SocketException {
  242. if (isClosedOrPending()) {
  243. throw new SocketException("Socket Closed");
  244. }
  245. if (opt == SO_TIMEOUT) {
  246. return new Integer(timeout);
  247. }
  248. int ret = 0;
  249. /*
  250. * The native socketGetOption() knows about 3 options.
  251. * The 32 bit value it returns will be interpreted according
  252. * to what we're asking. A return of -1 means it understands
  253. * the option but its turned off. It will raise a SocketException
  254. * if "opt" isn't one it understands.
  255. */
  256. switch (opt) {
  257. case TCP_NODELAY:
  258. ret = socketGetOption(opt, null);
  259. return Boolean.valueOf(ret != -1);
  260. case SO_OOBINLINE:
  261. ret = socketGetOption(opt, null);
  262. return Boolean.valueOf(ret != -1);
  263. case SO_LINGER:
  264. ret = socketGetOption(opt, null);
  265. return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret));
  266. case SO_REUSEADDR:
  267. ret = socketGetOption(opt, null);
  268. return Boolean.valueOf(ret != -1);
  269. case SO_BINDADDR:
  270. if (fd != null && fd1 != null ) {
  271. /* must be unbound or else bound to anyLocal */
  272. return anyLocalBoundAddr;
  273. }
  274. InetAddressContainer in = new InetAddressContainer();
  275. ret = socketGetOption(opt, in);
  276. return in.addr;
  277. case SO_SNDBUF:
  278. case SO_RCVBUF:
  279. ret = socketGetOption(opt, null);
  280. return new Integer(ret);
  281. case IP_TOS:
  282. ret = socketGetOption(opt, null);
  283. if (ret == -1) { // ipv6 tos
  284. return new Integer(trafficClass);
  285. } else {
  286. return new Integer(ret);
  287. }
  288. case SO_KEEPALIVE:
  289. ret = socketGetOption(opt, null);
  290. return Boolean.valueOf(ret != -1);
  291. // should never get here
  292. default:
  293. return null;
  294. }
  295. }
  296. /**
  297. * The workhorse of the connection operation. Tries several times to
  298. * establish a connection to the given <host, port>. If unsuccessful,
  299. * throws an IOException indicating what went wrong.
  300. */
  301. private synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
  302. try {
  303. FileDescriptor fd = acquireFD();
  304. try {
  305. socketConnect(address, port, timeout);
  306. // If we have a ref. to the Socket, then sets the flags
  307. // created, bound & connected to true.
  308. // This is normally done in Socket.connect() but some
  309. // subclasses of Socket may call impl.connect() directly!
  310. if (socket != null) {
  311. socket.setBound();
  312. socket.setConnected();
  313. }
  314. } finally {
  315. releaseFD();
  316. }
  317. } catch (IOException e) {
  318. close();
  319. throw e;
  320. }
  321. }
  322. /**
  323. * Binds the socket to the specified address of the specified local port.
  324. * @param address the address
  325. * @param port the port
  326. */
  327. protected synchronized void bind(InetAddress address, int lport)
  328. throws IOException
  329. {
  330. socketBind(address, lport);
  331. if (socket != null)
  332. socket.setBound();
  333. if (serverSocket != null)
  334. serverSocket.setBound();
  335. if (address.isAnyLocalAddress()) {
  336. anyLocalBoundAddr = address;
  337. }
  338. }
  339. /**
  340. * Listens, for a specified amount of time, for connections.
  341. * @param count the amount of time to listen for connections
  342. */
  343. protected synchronized void listen(int count) throws IOException {
  344. socketListen(count);
  345. }
  346. /**
  347. * Accepts connections.
  348. * @param s the connection
  349. */
  350. protected synchronized void accept(SocketImpl s) throws IOException {
  351. FileDescriptor fd = acquireFD();
  352. try {
  353. socketAccept(s);
  354. } finally {
  355. releaseFD();
  356. }
  357. }
  358. /**
  359. * Gets an InputStream for this socket.
  360. */
  361. protected synchronized InputStream getInputStream() throws IOException {
  362. if (isClosedOrPending()) {
  363. throw new IOException("Socket Closed");
  364. }
  365. if (shut_rd) {
  366. throw new IOException("Socket input is shutdown");
  367. }
  368. if (socketInputStream == null) {
  369. socketInputStream = new SocketInputStream(this);
  370. }
  371. return socketInputStream;
  372. }
  373. void setInputStream(SocketInputStream in) {
  374. socketInputStream = in;
  375. }
  376. /**
  377. * Gets an OutputStream for this socket.
  378. */
  379. protected synchronized OutputStream getOutputStream() throws IOException {
  380. if (isClosedOrPending()) {
  381. throw new IOException("Socket Closed");
  382. }
  383. if (shut_wr) {
  384. throw new IOException("Socket output is shutdown");
  385. }
  386. return new SocketOutputStream(this);
  387. }
  388. /**
  389. * Returns the number of bytes that can be read without blocking.
  390. */
  391. protected synchronized int available() throws IOException {
  392. if (isClosedOrPending()) {
  393. throw new IOException("Stream closed.");
  394. }
  395. /*
  396. * If connection has been reset then return 0 to indicate
  397. * there are no buffered bytes.
  398. */
  399. if (isConnectionReset()) {
  400. return 0;
  401. }
  402. /*
  403. * If no bytes available and we were previously notified
  404. * of a connection reset then we move to the reset state.
  405. *
  406. * If are notified of a connection reset then check
  407. * again if there are bytes buffered on the socket.
  408. */
  409. int n = 0;
  410. try {
  411. n = socketAvailable();
  412. if (n == 0 && isConnectionResetPending()) {
  413. setConnectionReset();
  414. }
  415. } catch (ConnectionResetException exc1) {
  416. setConnectionResetPending();
  417. try {
  418. n = socketAvailable();
  419. if (n == 0) {
  420. setConnectionReset();
  421. }
  422. } catch (ConnectionResetException exc2) {
  423. }
  424. }
  425. return n;
  426. }
  427. /**
  428. * Closes the socket.
  429. */
  430. protected void close() throws IOException {
  431. synchronized(fdLock) {
  432. if (fd != null || fd1 != null) {
  433. if (fdUseCount == 0) {
  434. if (closePending) {
  435. return;
  436. }
  437. closePending = true;
  438. /*
  439. * We close the FileDescriptor in two-steps - first the
  440. * "pre-close" which closes the socket but doesn't
  441. * release the underlying file descriptor. This operation
  442. * may be lengthy due to untransmitted data and a long
  443. * linger interval. Once the pre-close is done we do the
  444. * actual socket to release the fd.
  445. */
  446. try {
  447. socketPreClose();
  448. } finally {
  449. socketClose();
  450. }
  451. fd = null;
  452. fd1 = null;
  453. return;
  454. } else {
  455. /*
  456. * If a thread has acquired the fd and a close
  457. * isn't pending then use a deferred close.
  458. * Also decrement fdUseCount to signal the last
  459. * thread that releases the fd to close it.
  460. */
  461. if (!closePending) {
  462. closePending = true;
  463. fdUseCount--;
  464. socketPreClose();
  465. }
  466. }
  467. }
  468. }
  469. }
  470. /**
  471. * Shutdown read-half of the socket connection;
  472. */
  473. protected void shutdownInput() throws IOException {
  474. if (fd != null) {
  475. socketShutdown(SHUT_RD);
  476. if (socketInputStream != null) {
  477. socketInputStream.setEOF(true);
  478. }
  479. shut_rd = true;
  480. }
  481. }
  482. /**
  483. * Shutdown write-half of the socket connection;
  484. */
  485. protected void shutdownOutput() throws IOException {
  486. if (fd != null) {
  487. socketShutdown(SHUT_WR);
  488. shut_wr = true;
  489. }
  490. }
  491. protected boolean supportsUrgentData () {
  492. return true;
  493. }
  494. protected void sendUrgentData (int data) throws IOException {
  495. if (fd == null) {
  496. throw new IOException("Socket Closed");
  497. }
  498. socketSendUrgentData (data);
  499. }
  500. /**
  501. * Cleans up if the user forgets to close it.
  502. */
  503. protected void finalize() throws IOException {
  504. close();
  505. }
  506. /*
  507. * "Acquires" and returns the FileDescriptor for this impl
  508. *
  509. * A corresponding releaseFD is required to "release" the
  510. * FileDescriptor.
  511. */
  512. public final FileDescriptor acquireFD() {
  513. synchronized (fdLock) {
  514. fdUseCount++;
  515. return fd;
  516. }
  517. }
  518. /*
  519. * "Release" the FileDescriptor for this impl.
  520. *
  521. * If the use count goes to -1 then the socket is closed.
  522. */
  523. public final void releaseFD() {
  524. synchronized (fdLock) {
  525. fdUseCount--;
  526. if (fdUseCount == -1) {
  527. if (fd != null) {
  528. try {
  529. socketClose();
  530. } catch (IOException e) {
  531. } finally {
  532. fd = null;
  533. }
  534. }
  535. }
  536. }
  537. }
  538. public boolean isConnectionReset() {
  539. synchronized (resetLock) {
  540. return (resetState == CONNECTION_RESET);
  541. }
  542. }
  543. public boolean isConnectionResetPending() {
  544. synchronized (resetLock) {
  545. return (resetState == CONNECTION_RESET_PENDING);
  546. }
  547. }
  548. public void setConnectionReset() {
  549. synchronized (resetLock) {
  550. resetState = CONNECTION_RESET;
  551. }
  552. }
  553. public void setConnectionResetPending() {
  554. synchronized (resetLock) {
  555. if (resetState == CONNECTION_NOT_RESET) {
  556. resetState = CONNECTION_RESET_PENDING;
  557. }
  558. }
  559. }
  560. /*
  561. * Return true if already closed or close is pending
  562. */
  563. public boolean isClosedOrPending() {
  564. /*
  565. * Lock on fdLock to ensure that we wait if a
  566. * close is in progress.
  567. */
  568. synchronized (fdLock) {
  569. if (closePending || (fd == null && fd1 == null)) {
  570. return true;
  571. } else {
  572. return false;
  573. }
  574. }
  575. }
  576. /*
  577. * Return the current value of SO_TIMEOUT
  578. */
  579. public int getTimeout() {
  580. return timeout;
  581. }
  582. /*
  583. * "Pre-close" a socket by dup'ing the file descriptor - this enables
  584. * the socket to be closed without releasing the file descriptor.
  585. */
  586. private void socketPreClose() throws IOException {
  587. socketClose0(true);
  588. }
  589. /*
  590. * Close the socket (and release the file descriptor).
  591. */
  592. private void socketClose() throws IOException {
  593. socketClose0(false);
  594. }
  595. private native void socketCreate(boolean isServer) throws IOException;
  596. private native void socketConnect(InetAddress address, int port, int timeout)
  597. throws IOException;
  598. private native void socketBind(InetAddress address, int port)
  599. throws IOException;
  600. private native void socketListen(int count)
  601. throws IOException;
  602. private native void socketAccept(SocketImpl s)
  603. throws IOException;
  604. private native int socketAvailable()
  605. throws IOException;
  606. private native void socketClose0(boolean useDeferredClose)
  607. throws IOException;
  608. private native void socketShutdown(int howto)
  609. throws IOException;
  610. private static native void initProto();
  611. private native void socketSetOption(int cmd, boolean on, Object value)
  612. throws SocketException;
  613. private native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
  614. private native int socketGetOption1(int opt, Object iaContainerObj, FileDescriptor fd) throws SocketException;
  615. private native void socketSendUrgentData(int data)
  616. throws IOException;
  617. public final static int SHUT_RD = 0;
  618. public final static int SHUT_WR = 1;
  619. }
  620. class InetAddressContainer {
  621. InetAddress addr;
  622. }