1. /*
  2. * @(#)SocketInputStream.java 1.34 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.FileDescriptor;
  9. import java.io.FileInputStream;
  10. import java.io.IOException;
  11. import java.nio.channels.FileChannel;
  12. import sun.net.ConnectionResetException;
  13. /**
  14. * This stream extends FileInputStream to implement a
  15. * SocketInputStream. Note that this class should <b>NOT</b> be
  16. * public.
  17. *
  18. * @version 1.34, 12/19/03
  19. * @author Jonathan Payne
  20. * @author Arthur van Hoff
  21. */
  22. class SocketInputStream extends FileInputStream
  23. {
  24. static {
  25. init();
  26. }
  27. private boolean eof;
  28. private PlainSocketImpl impl = null;
  29. private byte temp[];
  30. private Socket socket = null;
  31. /**
  32. * Creates a new SocketInputStream. Can only be called
  33. * by a Socket. This method needs to hang on to the owner Socket so
  34. * that the fd will not be closed.
  35. * @param impl the implemented socket input stream
  36. */
  37. SocketInputStream(PlainSocketImpl impl) throws IOException {
  38. super(impl.getFileDescriptor());
  39. this.impl = impl;
  40. socket = impl.getSocket();
  41. }
  42. /**
  43. * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
  44. * object associated with this file input stream.</p>
  45. *
  46. * The <code>getChannel</code> method of <code>SocketInputStream</code>
  47. * returns <code>null</code> since it is a socket based stream.</p>
  48. *
  49. * @return the file channel associated with this file input stream
  50. *
  51. * @since 1.4
  52. * @spec JSR-51
  53. */
  54. public final FileChannel getChannel() {
  55. return null;
  56. }
  57. /**
  58. * Reads into an array of bytes at the specified offset using
  59. * the received socket primitive.
  60. * @param fd the FileDescriptor
  61. * @param b the buffer into which the data is read
  62. * @param off the start offset of the data
  63. * @param len the maximum number of bytes read
  64. * @param timeout the read timeout in ms
  65. * @return the actual number of bytes read, -1 is
  66. * returned when the end of the stream is reached.
  67. * @exception IOException If an I/O error has occurred.
  68. */
  69. private native int socketRead0(FileDescriptor fd,
  70. byte b[], int off, int len,
  71. int timeout)
  72. throws IOException;
  73. /**
  74. * Reads into a byte array data from the socket.
  75. * @param b the buffer into which the data is read
  76. * @return the actual number of bytes read, -1 is
  77. * returned when the end of the stream is reached.
  78. * @exception IOException If an I/O error has occurred.
  79. */
  80. public int read(byte b[]) throws IOException {
  81. return read(b, 0, b.length);
  82. }
  83. /**
  84. * Reads into a byte array <i>b</i> at offset <i>off</i>,
  85. * <i>length</i> bytes of data.
  86. * @param b the buffer into which the data is read
  87. * @param off the start offset of the data
  88. * @param len the maximum number of bytes read
  89. * @return the actual number of bytes read, -1 is
  90. * returned when the end of the stream is reached.
  91. * @exception IOException If an I/O error has occurred.
  92. */
  93. public int read(byte b[], int off, int length) throws IOException {
  94. int n;
  95. // EOF already encountered
  96. if (eof) {
  97. return -1;
  98. }
  99. // connection reset
  100. if (impl.isConnectionReset()) {
  101. throw new SocketException("Connection reset");
  102. }
  103. // bounds check
  104. if (length <= 0 || off < 0 || off + length > b.length) {
  105. if (length == 0) {
  106. return 0;
  107. }
  108. throw new ArrayIndexOutOfBoundsException();
  109. }
  110. boolean gotReset = false;
  111. // acquire file descriptor and do the read
  112. FileDescriptor fd = impl.acquireFD();
  113. try {
  114. n = socketRead0(fd, b, off, length, impl.getTimeout());
  115. if (n > 0) {
  116. return n;
  117. }
  118. } catch (ConnectionResetException rstExc) {
  119. gotReset = true;
  120. } finally {
  121. impl.releaseFD();
  122. }
  123. /*
  124. * We receive a "connection reset" but there may be bytes still
  125. * buffered on the socket
  126. */
  127. if (gotReset) {
  128. impl.setConnectionResetPending();
  129. impl.acquireFD();
  130. try {
  131. n = socketRead0(fd, b, off, length, impl.getTimeout());
  132. if (n > 0) {
  133. return n;
  134. }
  135. } catch (ConnectionResetException rstExc) {
  136. } finally {
  137. impl.releaseFD();
  138. }
  139. }
  140. /*
  141. * If we get here we are at EOF, the socket has been closed,
  142. * or the connection has been reset.
  143. */
  144. if (impl.isClosedOrPending()) {
  145. throw new SocketException("Socket closed");
  146. }
  147. if (impl.isConnectionResetPending()) {
  148. impl.setConnectionReset();
  149. }
  150. if (impl.isConnectionReset()) {
  151. throw new SocketException("Connection reset");
  152. }
  153. eof = true;
  154. return -1;
  155. }
  156. /**
  157. * Reads a single byte from the socket.
  158. */
  159. public int read() throws IOException {
  160. if (eof) {
  161. return -1;
  162. }
  163. temp = new byte[1];
  164. int n = read(temp, 0, 1);
  165. if (n <= 0) {
  166. return -1;
  167. }
  168. return temp[0] & 0xff;
  169. }
  170. /**
  171. * Skips n bytes of input.
  172. * @param n the number of bytes to skip
  173. * @return the actual number of bytes skipped.
  174. * @exception IOException If an I/O error has occurred.
  175. */
  176. public long skip(long numbytes) throws IOException {
  177. if (numbytes <= 0) {
  178. return 0;
  179. }
  180. long n = numbytes;
  181. int buflen = (int) Math.min(1024, n);
  182. byte data[] = new byte[buflen];
  183. while (n > 0) {
  184. int r = read(data, 0, (int) Math.min((long) buflen, n));
  185. if (r < 0) {
  186. break;
  187. }
  188. n -= r;
  189. }
  190. return numbytes - n;
  191. }
  192. /**
  193. * Returns the number of bytes that can be read without blocking.
  194. * @return the number of immediately available bytes
  195. */
  196. public int available() throws IOException {
  197. return impl.available();
  198. }
  199. /**
  200. * Closes the stream.
  201. */
  202. private boolean closing = false;
  203. public void close() throws IOException {
  204. // Prevent recursion. See BugId 4484411
  205. if (closing)
  206. return;
  207. closing = true;
  208. if (socket != null) {
  209. if (!socket.isClosed())
  210. socket.close();
  211. } else
  212. impl.close();
  213. closing = false;
  214. }
  215. void setEOF(boolean eof) {
  216. this.eof = eof;
  217. }
  218. /**
  219. * Overrides finalize, the fd is closed by the Socket.
  220. */
  221. protected void finalize() {}
  222. /**
  223. * Perform class load-time initializations.
  224. */
  225. private native static void init();
  226. }