/**
* OnionCoffee - Anonymous Communication through TOR Network
* Copyright (C) 2005-2007 RWTH Aachen University, Informatik IV
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package TorJava;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/**
* this class contains a backgroundthread that waits for incoming cells in a
* TCPStream and makes them available to the Java-Application.
*
* @author Lexi Pimenidis
* @author Andriy Panchenko
* @version unstable
* @see TCPStreamThreadJava2Tor
*/
class TCPStreamThreadTor2Java extends Thread {
TCPStream stream;
PipedInputStream sin; // read from tor and output to this stream
PipedOutputStream fromtor; // private end of this pipe
boolean stopped; // as stop() is depreacated we use this toggle variable
TCPStreamThreadTor2Java(TCPStream stream) {
this.stream = stream;
try {
sin = (PipedInputStream) new SafePipedInputStream();
fromtor = new PipedOutputStream(sin);
} catch (IOException e) {
Logger.logStream(Logger.ERROR,
"TCPStreamThreadTor2Java: caught IOException "
+ e.getMessage());
}
this.start();
}
public void close() {
this.stopped = true;
this.interrupt();
}
public void run() {
while (!stream.closed && !this.stopped) {
Cell cell = (Cell) stream.queue.get();
if (cell != null) {
if (!cell.isTypeRelay()) {
Logger.logStream(Logger.ERROR,
"TCPStreamThreadTor2Java.run(): stream "
+ stream.ID + " received NON-RELAY cell:\n"
+ cell.print());
} else {
CellRelay relay = (CellRelay) cell;
if (relay.isTypeData()) {
Logger.logStream(Logger.RAW_DATA,
"TCPStreamThreadTor2Java.run(): stream "
+ stream.ID + " received data");
try {
fromtor.write(relay.data, 0, relay.length);
} catch (IOException e) {
Logger.logStream(Logger.ERROR,
"TCPStreamThreadTor2Java.run(): caught IOException "
+ e.getMessage());
}
} else if (relay.isTypeEnd()) {
Logger.logStream(Logger.RAW_DATA,
"TCPStreamThreadTor2Java.run(): stream "
+ stream.ID + " is closed: "
+ relay.reasonForClosing());
stream.closed_for_reason = (int) (relay.payload[0]) & 0xff;
stream.closed = true;
stream.close(true);
} else {
Logger.logStream(Logger.ERROR,
"TCPStreamThreadTor2Java.run(): stream "
+ stream.ID
+ " received strange cell:\n"
+ relay.print());
}
}
}
}
}
}
/**
* this class is meant to simulate the behaviour of a standard stream. It's
* necessary because at some point the PipedInputStream returns a IOException,
* if the connection has been closed by the remote side, where a InputStream
* would only return a 'null'.
*
* @author Lexi Pimenidis
* @see PipedInputStream
* @see InputStream
*/
class SafePipedInputStream extends PipedInputStream {
public int read() throws IOException {
try {
return super.read();
} catch (IOException e) {
// catch only if the connected PipeOutputStream is closed. otherwise
// rethrow the error
String msg = e.getMessage();
if (msg!=null && msg.equals("Write end dead"))
return -1;
else
throw e;
}
}
public int read(byte[] b, int off, int len) throws IOException {
try {
return super.read(b, off, len);
} catch (IOException e) {
// catch only if the connected PipeOutputStream is closed. otherwise
// rethrow the error
String msg = e.getMessage();
if (msg!=null && (msg.equals("Write end dead") || msg.equals("Pipe closed"))) {
b = null;
return 0;
} else
throw e;
}
}
}