diff --git a/components/net/sf/briar/plugins/tor/TorPlugin.java b/components/net/sf/briar/plugins/tor/TorPlugin.java index 96130acf8c6809f1b70e3a47e1d061b60068cf94..3a450e6e13e062405019f64f796eb7d928306b3f 100644 --- a/components/net/sf/briar/plugins/tor/TorPlugin.java +++ b/components/net/sf/briar/plugins/tor/TorPlugin.java @@ -17,6 +17,7 @@ import net.sf.briar.api.plugins.duplex.DuplexTransportConnection; import net.sf.briar.api.protocol.TransportId; import net.sf.briar.util.StringUtils; +import org.silvertunnel.netlib.api.NetAddress; import org.silvertunnel.netlib.api.NetFactory; import org.silvertunnel.netlib.api.NetLayer; import org.silvertunnel.netlib.api.NetLayerIDs; @@ -43,9 +44,9 @@ class TorPlugin implements DuplexPlugin { private final DuplexPluginCallback callback; private final long pollingInterval; - private boolean running = false; // Locking: this - private NetServerSocket socket = null; // Locking: this + private boolean running = false, connected = false; // Locking: this private NetLayer netLayer = null; // Locking: this + private NetServerSocket socket = null; // Locking: this TorPlugin(@PluginExecutor Executor pluginExecutor, DuplexPluginCallback callback, long pollingInterval) { @@ -72,18 +73,18 @@ class TorPlugin implements DuplexPlugin { private void bind() { // Retrieve the hidden service address, or create one if necessary TorHiddenServicePrivateNetAddress addr; + TorNetLayerUtil util = TorNetLayerUtil.getInstance(); TransportConfig c = callback.getConfig(); String privateKey = c.get("privateKey"); if(privateKey == null) { - addr = createHiddenServiceAddress(c); + addr = createHiddenServiceAddress(util, c); } else { - TorNetLayerUtil util = TorNetLayerUtil.getInstance(); try { addr = util.parseTorHiddenServicePrivateNetAddressFromStrings( privateKey, "", false); } catch(IOException e) { if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); - addr = createHiddenServiceAddress(c); + addr = createHiddenServiceAddress(util, c); } } TorHiddenServicePortPrivateNetAddress addrPort = @@ -92,6 +93,15 @@ class TorPlugin implements DuplexPlugin { NetFactory netFactory = NetFactory.getInstance(); NetLayer nl = netFactory.getNetLayerById(NetLayerIDs.TOR); nl.waitUntilReady(); + synchronized(this) { + if(!running) { + tryToClear(nl); + return; + } + netLayer = nl; + connected = true; + notifyAll(); + } // Publish the hidden service NetServerSocket ss; try { @@ -106,7 +116,6 @@ class TorPlugin implements DuplexPlugin { return; } socket = ss; - netLayer = nl; } String onion = addr.getPublicOnionHostname(); if(LOG.isLoggable(Level.INFO)) LOG.info("Listening on " + onion); @@ -117,8 +126,7 @@ class TorPlugin implements DuplexPlugin { } private TorHiddenServicePrivateNetAddress createHiddenServiceAddress( - TransportConfig c) { - TorNetLayerUtil util = TorNetLayerUtil.getInstance(); + TorNetLayerUtil util, TransportConfig c) { TorHiddenServicePrivateNetAddress addr = util.createNewTorHiddenServicePrivateNetAddress(); RSAKeyPair keyPair = addr.getKeyPair(); @@ -128,6 +136,14 @@ class TorPlugin implements DuplexPlugin { return addr; } + private void tryToClear(NetLayer nl) { + try { + nl.clear(); + } catch(IOException e) { + if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); + } + } + private void tryToClose(NetServerSocket ss) { try { ss.close(); @@ -156,15 +172,17 @@ class TorPlugin implements DuplexPlugin { } public synchronized void stop() throws IOException { - running = false; - if(socket != null) { - tryToClose(socket); - socket = null; - } if(netLayer != null) { netLayer.clear(); netLayer = null; } + if(socket != null) { + tryToClose(socket); + socket = null; + } + running = false; + connected = false; + notifyAll(); } public boolean shouldPoll() { @@ -201,19 +219,28 @@ class TorPlugin implements DuplexPlugin { } public DuplexTransportConnection createConnection(ContactId c) { + NetLayer nl; synchronized(this) { - if(!running) return null; + while(!connected) { + if(!running) return null; + try { + wait(); + } catch(InterruptedException e) { + if(LOG.isLoggable(Level.INFO)) + LOG.info("Interrupted while waiting to connect"); + Thread.currentThread().interrupt(); + return null; + } + } + nl = netLayer; } TransportProperties p = callback.getRemoteProperties().get(c); if(p == null) return null; String onion = p.get("onion"); if(onion == null) return null; + NetAddress addr = new TcpipNetAddress(onion, 80); try { - TcpipNetAddress addr = new TcpipNetAddress(onion, 80); - NetFactory netFactory = NetFactory.getInstance(); - NetLayer netLayer = netFactory.getNetLayerById(NetLayerIDs.TOR); - netLayer.waitUntilReady(); - NetSocket s = netLayer.createNetSocket(null, null, addr); + NetSocket s = nl.createNetSocket(null, null, addr); return new TorTransportConnection(s); } catch(IOException e) { if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString()); diff --git a/test/net/sf/briar/plugins/tor/TorPluginTest.java b/test/net/sf/briar/plugins/tor/TorPluginTest.java index 6d54311b80cb4ea5494d02aff3d7b8e640ddbcfc..28ed8a65b11e1935383e2c9a663cc3ee9b9da489 100644 --- a/test/net/sf/briar/plugins/tor/TorPluginTest.java +++ b/test/net/sf/briar/plugins/tor/TorPluginTest.java @@ -1,7 +1,9 @@ package net.sf.briar.plugins.tor; +import java.io.PrintStream; import java.util.Hashtable; import java.util.Map; +import java.util.Scanner; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -40,10 +42,20 @@ public class TorPluginTest extends BriarTestCase { TorPlugin clientPlugin = new TorPlugin(e, clientCallback, 0L); clientPlugin.start(); // Connect to the server's hidden service - DuplexTransportConnection c = clientPlugin.createConnection(contactId); - assertNotNull(c); - c.dispose(false, false); - assertEquals(1, serverCallback.incomingConnections); + DuplexTransportConnection clientEnd = + clientPlugin.createConnection(contactId); + assertNotNull(clientEnd); + DuplexTransportConnection serverEnd = serverCallback.incomingConnection; + assertNotNull(serverEnd); + // Send some data through the Tor connection + PrintStream out = new PrintStream(clientEnd.getOutputStream()); + out.println("Hello world"); + out.flush(); + Scanner in = new Scanner(serverEnd.getInputStream()); + assertTrue(in.hasNextLine()); + assertEquals("Hello world", in.nextLine()); + serverEnd.dispose(false, false); + clientEnd.dispose(false, false); // Stop the plugins serverPlugin.stop(); clientPlugin.stop(); @@ -89,7 +101,7 @@ public class TorPluginTest extends BriarTestCase { private TransportConfig config = new TransportConfig(); private TransportProperties local = new TransportProperties(); - private volatile int incomingConnections = 0; + private volatile DuplexTransportConnection incomingConnection = null; public TransportConfig getConfig() { return config; @@ -108,8 +120,8 @@ public class TorPluginTest extends BriarTestCase { } public void setLocalProperties(TransportProperties p) { - latch.countDown(); local = p; + latch.countDown(); } public int showChoice(String[] options, String... message) { @@ -123,7 +135,7 @@ public class TorPluginTest extends BriarTestCase { public void showMessage(String... message) {} public void incomingConnectionCreated(DuplexTransportConnection d) { - incomingConnections++; + incomingConnection = d; } public void outgoingConnectionCreated(ContactId c,