mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-11-02 21:47:18 +00:00
Add cycle detecting locks, fix Orchid deadlock 2
https://github.com/subgraph/Orchid/pull/10 Conflicts: orchid/src/com/subgraph/orchid/circuits/CircuitIO.java
This commit is contained in:
@@ -156,6 +156,11 @@
|
|||||||
<version>4.11</version>
|
<version>4.11</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>16.0.1</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
45
orchid/src/com/subgraph/orchid/Threading.java
Normal file
45
orchid/src/com/subgraph/orchid/Threading.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package com.subgraph.orchid;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.CycleDetectingLockFactory;
|
||||||
|
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by android on 8/22/14.
|
||||||
|
*/
|
||||||
|
public class Threading {
|
||||||
|
static {
|
||||||
|
// Default policy goes here. If you want to change this, use one of the static methods before
|
||||||
|
// instantiating any orchid objects. The policy change will take effect only on new objects
|
||||||
|
// from that point onwards.
|
||||||
|
throwOnLockCycles();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CycleDetectingLockFactory.Policy policy;
|
||||||
|
public static CycleDetectingLockFactory factory;
|
||||||
|
|
||||||
|
public static ReentrantLock lock(String name) {
|
||||||
|
return factory.newReentrantLock(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void warnOnLockCycles() {
|
||||||
|
setPolicy(CycleDetectingLockFactory.Policies.WARN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void throwOnLockCycles() {
|
||||||
|
setPolicy(CycleDetectingLockFactory.Policies.THROW);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ignoreLockCycles() {
|
||||||
|
setPolicy(CycleDetectingLockFactory.Policies.DISABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setPolicy(CycleDetectingLockFactory.Policy policy) {
|
||||||
|
Threading.policy = policy;
|
||||||
|
factory = CycleDetectingLockFactory.newInstance(policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CycleDetectingLockFactory.Policy getPolicy() {
|
||||||
|
return policy;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ import com.subgraph.orchid.Connection;
|
|||||||
import com.subgraph.orchid.ConnectionIOException;
|
import com.subgraph.orchid.ConnectionIOException;
|
||||||
import com.subgraph.orchid.RelayCell;
|
import com.subgraph.orchid.RelayCell;
|
||||||
import com.subgraph.orchid.Stream;
|
import com.subgraph.orchid.Stream;
|
||||||
|
import com.subgraph.orchid.Threading;
|
||||||
import com.subgraph.orchid.TorException;
|
import com.subgraph.orchid.TorException;
|
||||||
import com.subgraph.orchid.circuits.cells.CellImpl;
|
import com.subgraph.orchid.circuits.cells.CellImpl;
|
||||||
import com.subgraph.orchid.circuits.cells.RelayCellImpl;
|
import com.subgraph.orchid.circuits.cells.RelayCellImpl;
|
||||||
@@ -36,11 +38,10 @@ public class CircuitIO implements DashboardRenderable {
|
|||||||
private final BlockingQueue<RelayCell> relayCellResponseQueue;
|
private final BlockingQueue<RelayCell> relayCellResponseQueue;
|
||||||
private final BlockingQueue<Cell> controlCellResponseQueue;
|
private final BlockingQueue<Cell> controlCellResponseQueue;
|
||||||
private final Map<Integer, StreamImpl> streamMap;
|
private final Map<Integer, StreamImpl> streamMap;
|
||||||
private final Object relaySendLock = new Object();
|
private final ReentrantLock streamLock = Threading.lock("stream");
|
||||||
|
private final ReentrantLock relaySendLock = Threading.lock("relaySend");
|
||||||
|
|
||||||
/** LOCKING: streamMap */
|
|
||||||
private boolean isMarkedForClose;
|
private boolean isMarkedForClose;
|
||||||
/** LOCKING: streamMap */
|
|
||||||
private boolean isClosed;
|
private boolean isClosed;
|
||||||
|
|
||||||
CircuitIO(CircuitImpl circuit, Connection connection, int circuitId) {
|
CircuitIO(CircuitImpl circuit, Connection connection, int circuitId) {
|
||||||
@@ -171,7 +172,8 @@ public class CircuitIO implements DashboardRenderable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized(streamMap) {
|
streamLock.lock();
|
||||||
|
try {
|
||||||
final StreamImpl stream = streamMap.get(cell.getStreamId());
|
final StreamImpl stream = streamMap.get(cell.getStreamId());
|
||||||
// It's not unusual for the stream to not be found. For example, if a RELAY_CONNECTED arrives after
|
// It's not unusual for the stream to not be found. For example, if a RELAY_CONNECTED arrives after
|
||||||
// the client has stopped waiting for it, the stream will never be tracked and eventually the edge node
|
// the client has stopped waiting for it, the stream will never be tracked and eventually the edge node
|
||||||
@@ -179,6 +181,8 @@ public class CircuitIO implements DashboardRenderable {
|
|||||||
if(stream != null) {
|
if(stream != null) {
|
||||||
stream.addInputCell(cell);
|
stream.addInputCell(cell);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
streamLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +191,8 @@ public class CircuitIO implements DashboardRenderable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sendRelayCellTo(RelayCell cell, CircuitNode targetNode) {
|
void sendRelayCellTo(RelayCell cell, CircuitNode targetNode) {
|
||||||
synchronized(relaySendLock) {
|
relaySendLock.lock();
|
||||||
|
try {
|
||||||
logRelayCell("Sending: ", cell);
|
logRelayCell("Sending: ", cell);
|
||||||
cell.setLength();
|
cell.setLength();
|
||||||
targetNode.updateForwardDigest(cell);
|
targetNode.updateForwardDigest(cell);
|
||||||
@@ -200,6 +205,8 @@ public class CircuitIO implements DashboardRenderable {
|
|||||||
targetNode.waitForSendWindowAndDecrement();
|
targetNode.waitForSendWindowAndDecrement();
|
||||||
|
|
||||||
sendCell(cell);
|
sendCell(cell);
|
||||||
|
} finally {
|
||||||
|
relaySendLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,20 +243,26 @@ public class CircuitIO implements DashboardRenderable {
|
|||||||
|
|
||||||
void markForClose() {
|
void markForClose() {
|
||||||
boolean shouldClose;
|
boolean shouldClose;
|
||||||
synchronized (streamMap) {
|
streamLock.lock();
|
||||||
|
try {
|
||||||
if(isMarkedForClose) {
|
if(isMarkedForClose) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isMarkedForClose = true;
|
isMarkedForClose = true;
|
||||||
shouldClose = streamMap.isEmpty();
|
shouldClose = streamMap.isEmpty();
|
||||||
|
} finally {
|
||||||
|
streamLock.unlock();
|
||||||
}
|
}
|
||||||
if(shouldClose)
|
if(shouldClose)
|
||||||
closeCircuit();
|
closeCircuit();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isMarkedForClose() {
|
boolean isMarkedForClose() {
|
||||||
synchronized (streamMap) {
|
streamLock.lock();
|
||||||
|
try {
|
||||||
return isMarkedForClose;
|
return isMarkedForClose;
|
||||||
|
} finally {
|
||||||
|
streamLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +289,8 @@ public class CircuitIO implements DashboardRenderable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void destroyCircuit() {
|
void destroyCircuit() {
|
||||||
synchronized(streamMap) {
|
streamLock.lock();
|
||||||
|
try {
|
||||||
if(isClosed) {
|
if(isClosed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -287,31 +301,42 @@ public class CircuitIO implements DashboardRenderable {
|
|||||||
s.close();
|
s.close();
|
||||||
}
|
}
|
||||||
isClosed = true;
|
isClosed = true;
|
||||||
|
} finally {
|
||||||
|
streamLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamImpl createNewStream(boolean autoclose) {
|
StreamImpl createNewStream(boolean autoclose) {
|
||||||
synchronized(streamMap) {
|
streamLock.lock();
|
||||||
|
try {
|
||||||
final int streamId = circuit.getStatus().nextStreamId();
|
final int streamId = circuit.getStatus().nextStreamId();
|
||||||
final StreamImpl stream = new StreamImpl(circuit, circuit.getFinalCircuitNode(), streamId, autoclose);
|
final StreamImpl stream = new StreamImpl(circuit, circuit.getFinalCircuitNode(), streamId, autoclose);
|
||||||
streamMap.put(streamId, stream);
|
streamMap.put(streamId, stream);
|
||||||
return stream;
|
return stream;
|
||||||
|
} finally {
|
||||||
|
streamLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeStream(StreamImpl stream) {
|
void removeStream(StreamImpl stream) {
|
||||||
boolean shouldClose;
|
boolean shouldClose;
|
||||||
synchronized(streamMap) {
|
streamLock.lock();
|
||||||
|
try {
|
||||||
streamMap.remove(stream.getStreamId());
|
streamMap.remove(stream.getStreamId());
|
||||||
shouldClose = streamMap.isEmpty() && isMarkedForClose;
|
shouldClose = streamMap.isEmpty() && isMarkedForClose;
|
||||||
|
} finally {
|
||||||
|
streamLock.unlock();
|
||||||
}
|
}
|
||||||
if(shouldClose)
|
if(shouldClose)
|
||||||
closeCircuit();
|
closeCircuit();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Stream> getActiveStreams() {
|
List<Stream> getActiveStreams() {
|
||||||
synchronized (streamMap) {
|
streamLock.lock();
|
||||||
|
try {
|
||||||
return new ArrayList<Stream>(streamMap.values());
|
return new ArrayList<Stream>(streamMap.values());
|
||||||
|
} finally {
|
||||||
|
streamLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import java.util.concurrent.Executors;
|
|||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import com.subgraph.orchid.Circuit;
|
import com.subgraph.orchid.Circuit;
|
||||||
import com.subgraph.orchid.CircuitBuildHandler;
|
import com.subgraph.orchid.CircuitBuildHandler;
|
||||||
@@ -29,6 +30,7 @@ import com.subgraph.orchid.OpenFailedException;
|
|||||||
import com.subgraph.orchid.Router;
|
import com.subgraph.orchid.Router;
|
||||||
import com.subgraph.orchid.Stream;
|
import com.subgraph.orchid.Stream;
|
||||||
import com.subgraph.orchid.StreamConnectFailedException;
|
import com.subgraph.orchid.StreamConnectFailedException;
|
||||||
|
import com.subgraph.orchid.Threading;
|
||||||
import com.subgraph.orchid.Tor;
|
import com.subgraph.orchid.Tor;
|
||||||
import com.subgraph.orchid.TorConfig;
|
import com.subgraph.orchid.TorConfig;
|
||||||
import com.subgraph.orchid.circuits.guards.EntryGuards;
|
import com.subgraph.orchid.circuits.guards.EntryGuards;
|
||||||
@@ -62,6 +64,7 @@ public class CircuitManagerImpl implements CircuitManager, DashboardRenderable {
|
|||||||
private final TorInitializationTracker initializationTracker;
|
private final TorInitializationTracker initializationTracker;
|
||||||
private final CircuitPathChooser pathChooser;
|
private final CircuitPathChooser pathChooser;
|
||||||
private final HiddenServiceManager hiddenServiceManager;
|
private final HiddenServiceManager hiddenServiceManager;
|
||||||
|
private final ReentrantLock lock = Threading.lock("circuitManager");
|
||||||
|
|
||||||
public CircuitManagerImpl(TorConfig config, DirectoryDownloaderImpl directoryDownloader, Directory directory, ConnectionCache connectionCache, TorInitializationTracker initializationTracker) {
|
public CircuitManagerImpl(TorConfig config, DirectoryDownloaderImpl directoryDownloader, Directory directory, ConnectionCache connectionCache, TorInitializationTracker initializationTracker) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
@@ -87,13 +90,19 @@ public class CircuitManagerImpl implements CircuitManager, DashboardRenderable {
|
|||||||
scheduledExecutor.scheduleAtFixedRate(circuitCreationTask, 0, 1000, TimeUnit.MILLISECONDS);
|
scheduledExecutor.scheduleAtFixedRate(circuitCreationTask, 0, 1000, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void stopBuildingCircuits(boolean killCircuits) {
|
public void stopBuildingCircuits(boolean killCircuits) {
|
||||||
scheduledExecutor.shutdownNow();
|
lock.lock();
|
||||||
if(killCircuits) {
|
|
||||||
List<CircuitImpl> circuits = new ArrayList<CircuitImpl>(activeCircuits);
|
try {
|
||||||
for(CircuitImpl c: circuits) {
|
scheduledExecutor.shutdownNow();
|
||||||
c.destroyCircuit();
|
if (killCircuits) {
|
||||||
|
List<CircuitImpl> circuits = new ArrayList<CircuitImpl>(activeCircuits);
|
||||||
|
for (CircuitImpl c : circuits) {
|
||||||
|
c.destroyCircuit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,8 +123,10 @@ public class CircuitManagerImpl implements CircuitManager, DashboardRenderable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized int getActiveCircuitCount() {
|
int getActiveCircuitCount() {
|
||||||
return activeCircuits.size();
|
synchronized (activeCircuits) {
|
||||||
|
return activeCircuits.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Circuit> getPendingCircuits() {
|
Set<Circuit> getPendingCircuits() {
|
||||||
@@ -126,17 +137,29 @@ public class CircuitManagerImpl implements CircuitManager, DashboardRenderable {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized int getPendingCircuitCount() {
|
int getPendingCircuitCount() {
|
||||||
return getPendingCircuits().size();
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
return getPendingCircuits().size();
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Circuit> getCircuitsByFilter(CircuitFilter filter) {
|
Set<Circuit> getCircuitsByFilter(CircuitFilter filter) {
|
||||||
final Set<Circuit> result = new HashSet<Circuit>();
|
final Set<Circuit> result = new HashSet<Circuit>();
|
||||||
|
final Set<CircuitImpl> circuits = new HashSet<CircuitImpl>();
|
||||||
|
|
||||||
synchronized (activeCircuits) {
|
synchronized (activeCircuits) {
|
||||||
for(CircuitImpl c: activeCircuits) {
|
// the filter might lock additional objects, causing a deadlock, so don't
|
||||||
if(filter == null || filter.filter(c)) {
|
// call it inside the monitor
|
||||||
result.add(c);
|
circuits.addAll(activeCircuits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(CircuitImpl c: circuits) {
|
||||||
|
if(filter == null || filter.filter(c)) {
|
||||||
|
result.add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ import com.subgraph.orchid.ConnectionHandshakeException;
|
|||||||
import com.subgraph.orchid.ConnectionIOException;
|
import com.subgraph.orchid.ConnectionIOException;
|
||||||
import com.subgraph.orchid.ConnectionTimeoutException;
|
import com.subgraph.orchid.ConnectionTimeoutException;
|
||||||
import com.subgraph.orchid.Router;
|
import com.subgraph.orchid.Router;
|
||||||
|
import com.subgraph.orchid.Threading;
|
||||||
import com.subgraph.orchid.Tor;
|
import com.subgraph.orchid.Tor;
|
||||||
import com.subgraph.orchid.TorConfig;
|
import com.subgraph.orchid.TorConfig;
|
||||||
import com.subgraph.orchid.TorException;
|
import com.subgraph.orchid.TorException;
|
||||||
@@ -61,9 +63,11 @@ public class ConnectionImpl implements Connection, DashboardRenderable {
|
|||||||
private boolean isConnected;
|
private boolean isConnected;
|
||||||
private volatile boolean isClosed;
|
private volatile boolean isClosed;
|
||||||
private final Thread readCellsThread;
|
private final Thread readCellsThread;
|
||||||
private final Object connectLock = new Object();
|
private final ReentrantLock connectLock = Threading.lock("connect");
|
||||||
|
private final ReentrantLock circuitsLock = Threading.lock("circuits");
|
||||||
|
private final ReentrantLock outputLock = Threading.lock("output");
|
||||||
private final AtomicLong lastActivity = new AtomicLong();
|
private final AtomicLong lastActivity = new AtomicLong();
|
||||||
|
|
||||||
|
|
||||||
public ConnectionImpl(TorConfig config, SSLSocket socket, Router router, TorInitializationTracker tracker, boolean isDirectoryConnection) {
|
public ConnectionImpl(TorConfig config, SSLSocket socket, Router router, TorInitializationTracker tracker, boolean isDirectoryConnection) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
@@ -92,13 +96,16 @@ public class ConnectionImpl implements Connection, DashboardRenderable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int bindCircuit(Circuit circuit) {
|
public int bindCircuit(Circuit circuit) {
|
||||||
synchronized(circuitMap) {
|
circuitsLock.lock();
|
||||||
|
try {
|
||||||
while(circuitMap.containsKey(currentId))
|
while(circuitMap.containsKey(currentId))
|
||||||
incrementNextId();
|
incrementNextId();
|
||||||
final int id = currentId;
|
final int id = currentId;
|
||||||
incrementNextId();
|
incrementNextId();
|
||||||
circuitMap.put(id, circuit);
|
circuitMap.put(id, circuit);
|
||||||
return id;
|
return id;
|
||||||
|
} finally {
|
||||||
|
circuitsLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +116,8 @@ public class ConnectionImpl implements Connection, DashboardRenderable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void connect() throws ConnectionFailedException, ConnectionTimeoutException, ConnectionHandshakeException {
|
void connect() throws ConnectionFailedException, ConnectionTimeoutException, ConnectionHandshakeException {
|
||||||
synchronized (connectLock) {
|
connectLock.lock();
|
||||||
|
try {
|
||||||
if(isConnected) {
|
if(isConnected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -128,6 +136,8 @@ public class ConnectionImpl implements Connection, DashboardRenderable {
|
|||||||
throw new ConnectionFailedException(e.getMessage());
|
throw new ConnectionFailedException(e.getMessage());
|
||||||
}
|
}
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
|
} finally {
|
||||||
|
connectLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +181,8 @@ public class ConnectionImpl implements Connection, DashboardRenderable {
|
|||||||
throw new ConnectionIOException("Cannot send cell because connection is not connected");
|
throw new ConnectionIOException("Cannot send cell because connection is not connected");
|
||||||
}
|
}
|
||||||
updateLastActivity();
|
updateLastActivity();
|
||||||
synchronized(output) {
|
outputLock.lock();
|
||||||
|
try {
|
||||||
try {
|
try {
|
||||||
output.write(cell.getCellBytes());
|
output.write(cell.getCellBytes());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -179,6 +190,8 @@ public class ConnectionImpl implements Connection, DashboardRenderable {
|
|||||||
closeSocket();
|
closeSocket();
|
||||||
throw new ConnectionIOException(e.getClass().getName() + " : "+ e.getMessage());
|
throw new ConnectionIOException(e.getClass().getName() + " : "+ e.getMessage());
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
outputLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,32 +289,41 @@ public class ConnectionImpl implements Connection, DashboardRenderable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processRelayCell(Cell cell) {
|
private void processRelayCell(Cell cell) {
|
||||||
synchronized(circuitMap) {
|
circuitsLock.lock();
|
||||||
|
try {
|
||||||
final Circuit circuit = circuitMap.get(cell.getCircuitId());
|
final Circuit circuit = circuitMap.get(cell.getCircuitId());
|
||||||
if(circuit == null) {
|
if(circuit == null) {
|
||||||
logger.warning("Could not deliver relay cell for circuit id = "+ cell.getCircuitId() +" on connection "+ this +". Circuit not found");
|
logger.warning("Could not deliver relay cell for circuit id = "+ cell.getCircuitId() +" on connection "+ this +". Circuit not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
circuit.deliverRelayCell(cell);
|
circuit.deliverRelayCell(cell);
|
||||||
|
} finally {
|
||||||
|
circuitsLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processControlCell(Cell cell) {
|
private void processControlCell(Cell cell) {
|
||||||
synchronized(circuitMap) {
|
circuitsLock.lock();
|
||||||
|
try {
|
||||||
final Circuit circuit = circuitMap.get(cell.getCircuitId());
|
final Circuit circuit = circuitMap.get(cell.getCircuitId());
|
||||||
if(circuit != null) {
|
if(circuit != null) {
|
||||||
circuit.deliverControlCell(cell);
|
circuit.deliverControlCell(cell);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
circuitsLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void idleCloseCheck() {
|
void idleCloseCheck() {
|
||||||
synchronized (circuitMap) {
|
circuitsLock.lock();
|
||||||
|
try {
|
||||||
final boolean needClose = (!isClosed && circuitMap.isEmpty() && getIdleMilliseconds() > CONNECTION_IDLE_TIMEOUT);
|
final boolean needClose = (!isClosed && circuitMap.isEmpty() && getIdleMilliseconds() > CONNECTION_IDLE_TIMEOUT);
|
||||||
if(needClose) {
|
if(needClose) {
|
||||||
logger.fine("Closing connection to "+ this +" on idle timeout");
|
logger.fine("Closing connection to "+ this +" on idle timeout");
|
||||||
closeSocket();
|
closeSocket();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
circuitsLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,8 +339,11 @@ public class ConnectionImpl implements Connection, DashboardRenderable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeCircuit(Circuit circuit) {
|
public void removeCircuit(Circuit circuit) {
|
||||||
synchronized(circuitMap) {
|
circuitsLock.lock();
|
||||||
|
try {
|
||||||
circuitMap.remove(circuit.getCircuitId());
|
circuitMap.remove(circuit.getCircuitId());
|
||||||
|
} finally {
|
||||||
|
circuitsLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,8 +353,11 @@ public class ConnectionImpl implements Connection, DashboardRenderable {
|
|||||||
|
|
||||||
public void dashboardRender(DashboardRenderer renderer, PrintWriter writer, int flags) throws IOException {
|
public void dashboardRender(DashboardRenderer renderer, PrintWriter writer, int flags) throws IOException {
|
||||||
final int circuitCount;
|
final int circuitCount;
|
||||||
synchronized (circuitMap) {
|
circuitsLock.lock();
|
||||||
|
try {
|
||||||
circuitCount = circuitMap.size();
|
circuitCount = circuitMap.size();
|
||||||
|
} finally {
|
||||||
|
circuitsLock.unlock();
|
||||||
}
|
}
|
||||||
if(circuitCount == 0 && (flags & DASHBOARD_CONNECTIONS_VERBOSE) == 0) {
|
if(circuitCount == 0 && (flags & DASHBOARD_CONNECTIONS_VERBOSE) == 0) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user