diff --git a/components/net/sf/briar/plugins/file/FilePlugin.java b/components/net/sf/briar/plugins/file/FilePlugin.java index eb8f70610c63938e58f64ab4f5309d3c7e59b09f..5bfec3d16a0b57b29794203c59a6d2604002ba54 100644 --- a/components/net/sf/briar/plugins/file/FilePlugin.java +++ b/components/net/sf/briar/plugins/file/FilePlugin.java @@ -79,7 +79,7 @@ abstract class FilePlugin implements BatchTransportPlugin { } public BatchTransportWriter createWriter(ContactId c) { - if(!started) throw new IllegalStateException(); + if(!started) return null; File dir = chooseOutputDirectory(); if(dir == null || !dir.exists() || !dir.isDirectory()) return null; File f = new File(dir, createFilename()); diff --git a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java index b4e6d72f0f7c05698ce067ecea297d6b60e047a1..bbfd2bc29dd7d06033ffde00f46d0cb67fbfca6f 100644 --- a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java +++ b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java @@ -69,7 +69,7 @@ implements RemovableDriveMonitor.Callback { for(int i = 0; i < paths.length; i++) { paths[i] = drives.get(i).getPath(); } - int i = callback.showChoice("REMOVABLE_DRIVE_CHOOSE_DRIVE", paths); + int i = callback.showChoice(paths, "REMOVABLE_DRIVE_CHOOSE_DRIVE"); if(i == -1) return null; return drives.get(i); } catch(IOException e) { diff --git a/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java b/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java index e8eef01c119e949c950bb6c6492c60c7ee4839d2..91035d63d22aa016a5b1261d024d4528863e01bd 100644 --- a/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java +++ b/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java @@ -1,6 +1,8 @@ package net.sf.briar.plugins.socket; +import java.io.IOException; import java.net.InetSocketAddress; +import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.util.Map; @@ -36,17 +38,34 @@ public class SimpleSocketPlugin extends SocketPlugin { @Override protected SocketAddress getLocalSocketAddress() { + assert localProperties != null; return createSocketAddress(localProperties); } @Override protected SocketAddress getSocketAddress(ContactId c) { + assert remoteProperties != null; Map<String, String> properties = remoteProperties.get(c); if(properties == null) return null; return createSocketAddress(properties); } + @Override + protected void setLocalSocketAddress(SocketAddress s) { + assert localProperties != null; + if(!(s instanceof InetSocketAddress)) + throw new IllegalArgumentException(); + InetSocketAddress i = (InetSocketAddress) s; + String host = i.getAddress().getHostAddress(); + String port = String.valueOf(i.getPort()); + // FIXME: Special handling for private IP addresses? + localProperties.put("host", host); + localProperties.put("port", port); + callback.setLocalProperties(localProperties); + } + private SocketAddress createSocketAddress(Map<String, String> properties) { + assert properties != null; String host = properties.get("host"); String portString = properties.get("port"); if(host == null || portString == null) return null; @@ -56,16 +75,16 @@ public class SimpleSocketPlugin extends SocketPlugin { } catch(NumberFormatException e) { return null; } - return InetSocketAddress.createUnresolved(host, port); + return new InetSocketAddress(host, port); } @Override - protected Socket createClientSocket() { + protected Socket createClientSocket() throws IOException { return new Socket(); } @Override - protected Socket createServerSocket() { - return new Socket(); + protected ServerSocket createServerSocket() throws IOException { + return new ServerSocket(); } } diff --git a/components/net/sf/briar/plugins/socket/SocketPlugin.java b/components/net/sf/briar/plugins/socket/SocketPlugin.java index a7a6c2ae04272b6e3b581280dc95a2d55e06a93f..abf94d60c90e291de1cc6706b6f1c907917a2899 100644 --- a/components/net/sf/briar/plugins/socket/SocketPlugin.java +++ b/components/net/sf/briar/plugins/socket/SocketPlugin.java @@ -1,6 +1,7 @@ package net.sf.briar.plugins.socket; import java.io.IOException; +import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.util.Map; @@ -21,14 +22,16 @@ abstract class SocketPlugin implements StreamTransportPlugin { protected Map<ContactId, Map<String, String>> remoteProperties = null; protected Map<String, String> config = null; protected StreamTransportCallback callback = null; + protected ServerSocket socket = null; private volatile boolean started = false; // These methods should be called with this's lock held and started == true protected abstract SocketAddress getLocalSocketAddress(); protected abstract SocketAddress getSocketAddress(ContactId c); - protected abstract Socket createClientSocket(); - protected abstract Socket createServerSocket(); + protected abstract void setLocalSocketAddress(SocketAddress s); + protected abstract Socket createClientSocket() throws IOException; + protected abstract ServerSocket createServerSocket() throws IOException; SocketPlugin(Executor executor) { this.executor = executor; @@ -51,25 +54,32 @@ abstract class SocketPlugin implements StreamTransportPlugin { return new Runnable() { public void run() { SocketAddress addr; - Socket s; - synchronized(SocketPlugin.this) { - if(!started) return; - addr = getLocalSocketAddress(); - s = createServerSocket(); - } - if(addr == null || s == null) return; + ServerSocket s; try { + synchronized(SocketPlugin.this) { + if(!started) return; + addr = getLocalSocketAddress(); + s = createServerSocket(); + } + if(addr == null || s == null) return; s.bind(addr); } catch(IOException e) { + // FIXME: Logging return; } + synchronized(SocketPlugin.this) { + if(!started) return; + socket = s; + setLocalSocketAddress(s.getLocalSocketAddress()); + } } }; } - public synchronized void stop() { + public synchronized void stop() throws IOException { if(!started) throw new IllegalStateException(); started = false; + if(socket != null) socket.close(); } public synchronized void setLocalProperties(Map<String, String> properties) @@ -103,7 +113,11 @@ abstract class SocketPlugin implements StreamTransportPlugin { return new Runnable() { public void run() { StreamTransportConnection conn = createAndConnectSocket(c); - if(conn != null) callback.outgoingConnectionCreated(c, conn); + if(conn != null) { + synchronized(SocketPlugin.this) { + if(started) callback.outgoingConnectionCreated(c, conn); + } + } } }; } @@ -111,13 +125,13 @@ abstract class SocketPlugin implements StreamTransportPlugin { protected StreamTransportConnection createAndConnectSocket(ContactId c) { SocketAddress addr; Socket s; - synchronized(this) { - if(!started) return null; - addr = getSocketAddress(c); - s = createClientSocket(); - } - if(addr == null || s == null) return null; try { + synchronized(this) { + if(!started) return null; + addr = getSocketAddress(c); + s = createClientSocket(); + } + if(addr == null || s == null) return null; s.connect(addr); } catch(IOException e) { return null; @@ -126,7 +140,6 @@ abstract class SocketPlugin implements StreamTransportPlugin { } public StreamTransportConnection createConnection(ContactId c) { - if(!started) throw new IllegalStateException(); - return createAndConnectSocket(c); + return started ? createAndConnectSocket(c) : null; } } diff --git a/test/build.xml b/test/build.xml index 163bbbc6ea1eb1200c14eb19a65705d89ac45385..3731461591563dadf2385ab24897ea9c24fc452c 100644 --- a/test/build.xml +++ b/test/build.xml @@ -31,6 +31,7 @@ <test name='net.sf.briar.plugins.file.PollingRemovableDriveMonitorTest'/> <test name='net.sf.briar.plugins.file.RemovableDrivePluginTest'/> <test name='net.sf.briar.plugins.file.UnixRemovableDriveMonitorTest'/> + <test name='net.sf.briar.plugins.socket.SimpleSocketPluginTest'/> <test name='net.sf.briar.protocol.AckReaderTest'/> <test name='net.sf.briar.protocol.BatchReaderTest'/> <test name='net.sf.briar.protocol.ConsumersTest'/> diff --git a/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java b/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java new file mode 100644 index 0000000000000000000000000000000000000000..aaa0e3b8e80afe31c312940c75dc59c82c1d9e8e --- /dev/null +++ b/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java @@ -0,0 +1,86 @@ +package net.sf.briar.plugins.socket; + +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.Executor; + +import junit.framework.TestCase; +import net.sf.briar.api.ContactId; +import net.sf.briar.api.transport.stream.StreamTransportCallback; +import net.sf.briar.api.transport.stream.StreamTransportConnection; + +import org.junit.Before; +import org.junit.Test; + +public class SimpleSocketPluginTest extends TestCase { + + private final ContactId contactId = new ContactId(0); + + private Map<String, String> localProperties = null; + private Map<ContactId, Map<String, String>> remoteProperties = null; + private Map<String, String> config = null; + + @Before + public void setUp() { + localProperties = new TreeMap<String, String>(); + remoteProperties = new HashMap<ContactId, Map<String, String>>(); + remoteProperties.put(contactId, new TreeMap<String, String>()); + config = new TreeMap<String, String>(); + } + + @Test + public void testBind() throws Exception { + StubCallback callback = new StubCallback(); + localProperties.put("host", "127.0.0.1"); + localProperties.put("port", "0"); + SimpleSocketPlugin plugin = + new SimpleSocketPlugin(new ImmediateExecutor(), 10); + plugin.start(localProperties, remoteProperties, config, callback); + assertNotNull(callback.localProperties); + String host = callback.localProperties.get("host"); + assertNotNull(host); + assertEquals("127.0.0.1", host); + String port = callback.localProperties.get("port"); + assertNotNull(port); + assertTrue(Integer.valueOf(port) > 0 && Integer.valueOf(port) < 65536); + plugin.stop(); + } + + private static class ImmediateExecutor implements Executor { + + public void execute(Runnable r) { + r.run(); + } + } + + private static class StubCallback implements StreamTransportCallback { + + private Map<String, String> localProperties = null; + + public void setLocalProperties(Map<String, String> properties) { + localProperties = properties; + } + + public void setConfig(Map<String, String> config) { + } + + public void showMessage(String... message) { + } + + public boolean showConfirmationMessage(String... message) { + return false; + } + + public int showChoice(String[] choices, String... message) { + return -1; + } + + public void incomingConnectionCreated(StreamTransportConnection c) { + } + + public void outgoingConnectionCreated(ContactId contactId, + StreamTransportConnection c) { + } + } +}