001: /*
002: * @(#)SocketInputStream.java 1.31 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.net;
029:
030: import java.io.FileDescriptor;
031: import java.io.FileInputStream;
032: import java.io.IOException;
033:
034: import sun.net.ConnectionResetException;
035:
036: /**
037: * This stream extends FileInputStream to implement a
038: * SocketInputStream. Note that this class should <b>NOT</b> be
039: * public.
040: *
041: * @version 1.23, 02/02/00
042: * @author Jonathan Payne
043: * @author Arthur van Hoff
044: */
045: class SocketInputStream extends FileInputStream {
046: static {
047: init();
048: }
049:
050: private boolean eof;
051: private PlainSocketImpl impl = null;
052: private byte temp[];
053: private Socket socket = null;
054:
055: /**
056: * Creates a new SocketInputStream. Can only be called
057: * by a Socket. This method needs to hang on to the owner Socket so
058: * that the fd will not be closed.
059: * @param impl the implemented socket input stream
060: */
061: SocketInputStream(PlainSocketImpl impl) throws IOException {
062: super (impl.getFileDescriptor());
063: this .impl = impl;
064: socket = impl.getSocket();
065: }
066:
067: /**
068: * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
069: * object associated with this file input stream.</p>
070: *
071: * The <code>getChannel</code> method of <code>SocketInputStream</code>
072: * returns <code>null</code> since it is a socket based stream.</p>
073: *
074: * @return the file channel associated with this file input stream
075: *
076: * @since 1.4
077: * @spec JSR-51
078: */
079: /* NOTE: No NIO in CDC
080: public final FileChannel getChannel() {
081: return null;
082: }
083: */
084: /**
085: * Reads into an array of bytes at the specified offset using
086: * the received socket primitive.
087: * @param fd the FileDescriptor
088: * @param b the buffer into which the data is read
089: * @param off the start offset of the data
090: * @param len the maximum number of bytes read
091: * @param timeout the read timeout in ms
092: * @return the actual number of bytes read, -1 is
093: * returned when the end of the stream is reached.
094: * @exception IOException If an I/O error has occurred.
095: */
096: private native int socketRead0(FileDescriptor fd, byte b[],
097: int off, int len, int timeout) throws IOException;
098:
099: /**
100: * Reads into a byte array data from the socket.
101: * @param b the buffer into which the data is read
102: * @return the actual number of bytes read, -1 is
103: * returned when the end of the stream is reached.
104: * @exception IOException If an I/O error has occurred.
105: */
106: public int read(byte b[]) throws IOException {
107: return read(b, 0, b.length);
108: }
109:
110: /**
111: * Reads into a byte array <i>b</i> at offset <i>off</i>,
112: * <i>length</i> bytes of data.
113: * @param b the buffer into which the data is read
114: * @param off the start offset of the data
115: * @param len the maximum number of bytes read
116: * @return the actual number of bytes read, -1 is
117: * returned when the end of the stream is reached.
118: * @exception IOException If an I/O error has occurred.
119: */
120: public int read(byte b[], int off, int length) throws IOException {
121: int n;
122:
123: // EOF already encountered
124: if (eof) {
125: return -1;
126: }
127:
128: // connection reset
129: if (impl.isConnectionReset()) {
130: throw new SocketException("Connection reset");
131: }
132:
133: // bounds check
134: if (length <= 0 || off < 0 || off + length > b.length) {
135: if (length == 0) {
136: return 0;
137: }
138: throw new ArrayIndexOutOfBoundsException();
139: }
140:
141: boolean gotReset = false;
142:
143: // acquire file descriptor and do the read
144: FileDescriptor fd = impl.acquireFD();
145: try {
146: n = socketRead0(fd, b, off, length, impl.getTimeout());
147: if (n > 0) {
148: return n;
149: }
150: } catch (ConnectionResetException rstExc) {
151: gotReset = true;
152: } finally {
153: impl.releaseFD();
154: }
155:
156: /*
157: * We receive a "connection reset" but there may be bytes still
158: * buffered on the socket
159: */
160: if (gotReset) {
161: impl.setConnectionResetPending();
162: impl.acquireFD();
163: try {
164: n = socketRead0(fd, b, off, length, impl.getTimeout());
165: if (n > 0) {
166: return n;
167: }
168: } catch (ConnectionResetException rstExc) {
169: } finally {
170: impl.releaseFD();
171: }
172: }
173:
174: /*
175: * If we get here we are at EOF, the socket has been closed,
176: * or the connection has been reset.
177: */
178: if (impl.isClosedOrPending()) {
179: throw new SocketException("Socket closed");
180: }
181: if (impl.isConnectionResetPending()) {
182: impl.setConnectionReset();
183: }
184: if (impl.isConnectionReset()) {
185: throw new SocketException("Connection reset");
186: }
187: eof = true;
188: return -1;
189: }
190:
191: /**
192: * Reads a single byte from the socket.
193: */
194: public int read() throws IOException {
195: if (eof) {
196: return -1;
197: }
198: temp = new byte[1];
199: int n = read(temp, 0, 1);
200: if (n <= 0) {
201: return -1;
202: }
203: return temp[0] & 0xff;
204: }
205:
206: /**
207: * Skips n bytes of input.
208: * @param n the number of bytes to skip
209: * @return the actual number of bytes skipped.
210: * @exception IOException If an I/O error has occurred.
211: */
212: public long skip(long numbytes) throws IOException {
213: if (numbytes <= 0) {
214: return 0;
215: }
216: long n = numbytes;
217: int buflen = (int) Math.min(1024, n);
218: byte data[] = new byte[buflen];
219: while (n > 0) {
220: int r = read(data, 0, (int) Math.min((long) buflen, n));
221: if (r < 0) {
222: break;
223: }
224: n -= r;
225: }
226: return numbytes - n;
227: }
228:
229: /**
230: * Returns the number of bytes that can be read without blocking.
231: * @return the number of immediately available bytes
232: */
233: public int available() throws IOException {
234: return impl.available();
235: }
236:
237: /**
238: * Closes the stream.
239: */
240: private boolean closing = false;
241:
242: public void close() throws IOException {
243: // Prevent recursion. See BugId 4484411
244: if (closing)
245: return;
246: closing = true;
247: if (socket != null) {
248: if (!socket.isClosed())
249: socket.close();
250: } else
251: impl.close();
252: closing = false;
253: }
254:
255: void setEOF(boolean eof) {
256: this .eof = eof;
257: }
258:
259: /**
260: * Overrides finalize, the fd is closed by the Socket.
261: */
262: protected void finalize() {
263: }
264:
265: /**
266: * Perform class load-time initializations.
267: */
268: private native static void init();
269: }
|