Name: boT120536 Date: 01/22/2001
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)
When a DataInputStream is layered on top of a SocketInputStream (or any other
input stream which may generate a restartable exception such as an
InterruptedIOException, the data input stream may lose data.
Operations such as readInt, readFully, readUTF, etc. all perform multiple read
calls to the underlying stream, and if any except the first call takes an
InterruptedIOException, say due to a socket timeout, the partial data already
read is discarded.
The following examples demonstrate the problem. The transmitter sends a series
of integer values using a DataOutputStream layered on a stream designed to get
maximum packet fragmentation (ie. each byte should be sent in its own packet)
with a delay between packets to simulate line delays such as TCP
retransmissions. The receiver tries to read integers from a DataInputStream
layered over a stream to monitor the number of characters actually read from
the socket, with a socket timeout set on the socket. When the two programs are
run, the transmitter sends its data, and the receiver reads data from the
stream and delviers nothing to the caller.
I consider this to be potentially very serious as it corrupts data, and
underlies many other things such as ObjectInputStream, etc.
Note - this may be the cause of some of the problems reported in Bug Id 4032593
DataRecv.java:
package com.hotstarttech.test;
import java.io.*;
import java.net.*;
public class DataRecv {
public static void main(String[] args) {
try {
ServerSocket l = new ServerSocket(10000);
Socket s = l.accept();
InputStream str = s.getInputStream();
MonitorInputStream monitor = new MonitorInputStream(str);
DataInputStream data = new DataInputStream(monitor);
s.setSoTimeout(100);
System.out.println ("Connected...");
for (int i = 0 ; i < 100 ; i++) {
try {
int value = data.readInt();
System.out.println ("read " + value);
} catch (InterruptedIOException ex) {
System.err.println("interrupted");
}
}
System.out.println("Read " + monitor.getCount() + " bytes");
data.close();
s.close();
l.close();;
} catch (IOException ex) {
System.err.println ("IO Exception - " + ex);
ex.printStackTrace();
}
}
}
class MonitorInputStream extends FilterInputStream {
int count = 0;
public MonitorInputStream (InputStream str) {
super(str);
}
public int read() throws IOException {
int c = in.read();
count++;
return c;
}
public int read(byte[] buffer, int off, int len) throws IOException {
int nread = in.read(buffer, off, len);
count += nread;
return nread;
}
public int getCount() {
return count;
}
}
DataXmit.java:
package com.hotstarttech.test;
import java.net.*;
import java.io.*;
public class DataXmit {
public static void main(String[] args) {
try {
Socket s = new Socket("localhost", 10000);
OutputStream str = s.getOutputStream();
BrokenOutputStream broke = new BrokenOutputStream(str);
DataOutputStream data = new DataOutputStream(broke);
s.setTcpNoDelay(true);
for (int i = 0 ; i < 50 ; i++) {
data.writeInt(i);
System.out.println ("Sent " + i);
}
data.close();
} catch (IOException ex) {
System.err.println ("IO Exception - " + ex);
ex.printStackTrace();
}
}
}
// this stream should cause maximum fragmentation of the output stream by
// inserting delays and writing and flushing single bytes
class BrokenOutputStream extends FilterOutputStream {
public BrokenOutputStream(OutputStream s) {
super(s);
}
public void write(int b) throws IOException {
try {
Thread.sleep(110);
} catch (InterruptedException ex) {}
out.write(b);
out.flush();
}
}
(Review ID: 113677)
======================================================================