package org.torproject.jtor.circuits.impl;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.torproject.jtor.TorException;
import org.torproject.jtor.crypto.TorRandom;
import org.torproject.jtor.directory.Router;
public class CircuitStatus {
private final static int MAXIMUM_TIMEOUT_COUNT = 3;
enum CircuitState {
UNCONNECTED("Unconnected"),
BUILDING("Building"),
FAILED("Failed"),
OPEN("Open"),
DESTROYED("Destroyed");
String name;
CircuitState(String name) { this.name = name; }
public String toString() { return name; }
}
private Date timestampCreated;
private Date timestampDirty;
private int streamTimeoutErrorCount = 0;
private int currentStreamId;
private Object streamIdLock = new Object();
private CircuitState state = CircuitState.UNCONNECTED;
private List<Router> circuitPath = Collections.emptyList();
CircuitStatus() {
initializeCurrentStreamId();
}
private void initializeCurrentStreamId() {
final TorRandom random = new TorRandom();
currentStreamId = random.nextInt(0xFFFF) + 1;
}
synchronized boolean countStreamTimeout() {
streamTimeoutErrorCount++;
return streamTimeoutErrorCount >= MAXIMUM_TIMEOUT_COUNT;
}
synchronized void updateCreatedTimestamp() {
timestampCreated = new Date();
timestampDirty = timestampCreated;
}
synchronized void updateDirtyTimestamp() {
timestampDirty = new Date();
}
synchronized long getMillisecondsElapsedSinceCreated() {
return millisecondsElapsedSince(timestampCreated);
}
synchronized long getMillisecondsIdle() {
return millisecondsElapsedSince(timestampDirty);
}
private static long millisecondsElapsedSince(Date then) {
if(then == null)
return 0;
final Date now = new Date();
return now.getTime() - then.getTime();
}
synchronized boolean isDirty() {
return timestampDirty != timestampCreated;
}
void setStateConnected() {
state = CircuitState.OPEN;
}
void setStateBuilding(List<Router> circuitPath) {
state = CircuitState.BUILDING;
this.circuitPath = Collections.unmodifiableList(circuitPath);
}
Router getFinalRouter() {
if(state == CircuitState.UNCONNECTED)
throw new TorException("Cannot retrieve last router from UNCONNECTED circuit");
if(circuitPath.size() == 0)
throw new TorException("No routers on circuit (?!)");
return circuitPath.get(circuitPath.size() - 1);
}
List<Router> getCircuitPath() {
return circuitPath;
}
void setStateFailed() {
state = CircuitState.FAILED;
}
void setStateOpen() {
state = CircuitState.OPEN;
}
void setStateDestroyed() {
state = CircuitState.DESTROYED;
}
boolean isBuilding() {
return state == CircuitState.BUILDING;
}
boolean isConnected() {
return state == CircuitState.OPEN;
}
boolean isUnconnected() {
return state == CircuitState.UNCONNECTED;
}
String getStateAsString() {
return state.toString();
}
int nextStreamId() {
synchronized(streamIdLock) {
currentStreamId++;
if(currentStreamId > 0xFFFF)
currentStreamId = 1;
return currentStreamId;
}
}
}