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