/**
* 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.Common;
import java.util.*;
import java.io.IOException;
import TorJava.Cell;
import TorJava.CellRelay;
/**
* a helper class for queueing data (FIFO)
*
* @author Lexi Pimenidis
* @version unstable
*/
public class Queue {
final int WAIT = 100;
volatile public boolean closed;
volatile private boolean addClosed;
public int timeout = 5000; // timeout internally represented in ms
private Vector<Object> queue;
private Vector<QueueHandler> handler;
/**
* init class
*
* @param timeout
* queue timeout in seconds
*/
public Queue(int timeout) {
this.closed = false;
this.addClosed = false;
this.timeout = timeout * 1000;
queue = new Vector<Object>();
handler = new Vector<QueueHandler>();
}
public Queue() {
this(1000);
}
public synchronized void addHandler(QueueHandler qh) {
handler.add(qh);
}
public synchronized boolean removeHandler(QueueHandler qh) {
return handler.remove(qh);
}
/** add a cell to the queue */
public synchronized void add(Object o) {
if (addClosed)
return;
/* first check if there are handlers installed */
try {
Cell cell = (Cell) o;
for(int i=0;i<handler.size();++i) {
try {
QueueHandler qh = (QueueHandler)handler.elementAt(i);
if (qh.handleCell(cell)) return;
}
catch(TorException te) { /* die silently */}
};
}
catch(ClassCastException e) {}
/* otherwise add to queue */
queue.add(o);
this.notify();
}
/**
* close the queue and remove all pending messages
*/
public synchronized void close() {
addClosed = true;
closed = true;
for(int i=0;i<handler.size();++i) {
QueueHandler qh = (QueueHandler)handler.elementAt(i);
qh.close();
}
queue.clear();
this.notify();
}
/**
* prohibit further writing to the queue
*/
public synchronized void closeAdd() {
addClosed = true;
this.notify();
}
/** determines wether the queue is empty */
boolean isEmpty() {
if (closed)
return true;
return queue.size() == 0;
}
public Object get() {
return get(timeout);
}
/**
* get the first element from out of the class. Behaviour
*
* @param timeout
* determines what will happen, if no data is in queue.
* @return a Cell or null
*/
public synchronized Object get(int timeout) {
boolean forever = false;
if (timeout == -1)
forever = true;
int retries = timeout / WAIT;
do {
if (closed)
return null;
if (queue.size() > 0) {
Object o = queue.get(0);
queue.remove(0);
return o;
} else if (addClosed) {
closed = true;
return null;
}
try {
// wait for data
wait(WAIT);
} catch (InterruptedException e) {
}
--retries;
} while (forever || (retries > 0) || (queue.size() > 0));
return null;
}
/**
* interface to receive a cell that is not a relay-cell
*/
public Cell receiveCell(int type) throws IOException, TorException, TorNoAnswerException {
Cell cell = (Cell) get();
if (cell == null)
throw new TorNoAnswerException("Queue.receiveCell: no answer after " + this.timeout / 1000 + " s", this.timeout / 1000);
if (cell.command != type)
throw new TorException("Queue.receiveCell: expected cell of type "
+ Cell.type(type) + " received type " + cell.type());
// if (cell.command == Cell.CELL_RELAY)
// Tor.log.logCell(Logger.WARNING,"used from interface for receiving a
// cell");
return cell;
}
/**
* interface to receive a relay-cell
*/
public CellRelay receiveRelayCell(int type) throws IOException, TorException, TorNoAnswerException {
CellRelay relay = (CellRelay) receiveCell(Cell.CELL_RELAY);
if (relay.relay_command != type) {
if ((relay.relay_command == CellRelay.RELAY_END)
&& (relay.data != null)) {
if (relay.data[0] == 2)
throw new TorResolveFailedException(); // Address not found
else
throw new TorException(
"Queue.receiveRelayCell: expected relay-cell of type "
+ CellRelay.relayCommand(type)
+ ", received END-CELL for reason: "
+ relay.reasonForClosing());
} else
throw new TorException(
"Queue.receiveRelayCell: expected relay-cell of type "
+ CellRelay.relayCommand(type)
+ " received type " + relay.relayCommand());
}
return relay;
}
}