diff --git a/briar-api/src/org/briarproject/api/event/ConnectionClosedEvent.java b/briar-api/src/org/briarproject/api/event/ConnectionClosedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..29030edcc4e382b0aa3392823fc51fe7a1ec2862 --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/ConnectionClosedEvent.java @@ -0,0 +1,30 @@ +package org.briarproject.api.event; + +import org.briarproject.api.TransportId; +import org.briarproject.api.contact.ContactId; + +public class ConnectionClosedEvent extends Event { + + private final ContactId contactId; + private final TransportId transportId; + private final boolean incoming; + + public ConnectionClosedEvent(ContactId contactId, TransportId transportId, + boolean incoming) { + this.contactId = contactId; + this.transportId = transportId; + this.incoming = incoming; + } + + public ContactId getContactId() { + return contactId; + } + + public TransportId getTransportId() { + return transportId; + } + + public boolean isIncoming() { + return incoming; + } +} diff --git a/briar-api/src/org/briarproject/api/event/ConnectionOpenedEvent.java b/briar-api/src/org/briarproject/api/event/ConnectionOpenedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..2143eb37a035b4e79c7887354cc38115b891cdfb --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/ConnectionOpenedEvent.java @@ -0,0 +1,30 @@ +package org.briarproject.api.event; + +import org.briarproject.api.TransportId; +import org.briarproject.api.contact.ContactId; + +public class ConnectionOpenedEvent extends Event { + + private final ContactId contactId; + private final TransportId transportId; + private final boolean incoming; + + public ConnectionOpenedEvent(ContactId contactId, TransportId transportId, + boolean incoming) { + this.contactId = contactId; + this.transportId = transportId; + this.incoming = incoming; + } + + public ContactId getContactId() { + return contactId; + } + + public TransportId getTransportId() { + return transportId; + } + + public boolean isIncoming() { + return incoming; + } +} diff --git a/briar-api/src/org/briarproject/api/plugins/ConnectionRegistry.java b/briar-api/src/org/briarproject/api/plugins/ConnectionRegistry.java index dc9376195387a5da851a9aab37a67707bc470e1c..6afc50acecd28015f61e0c92502faffdaae28ad9 100644 --- a/briar-api/src/org/briarproject/api/plugins/ConnectionRegistry.java +++ b/briar-api/src/org/briarproject/api/plugins/ConnectionRegistry.java @@ -10,9 +10,9 @@ import java.util.Collection; */ public interface ConnectionRegistry { - void registerConnection(ContactId c, TransportId t); + void registerConnection(ContactId c, TransportId t, boolean incoming); - void unregisterConnection(ContactId c, TransportId t); + void unregisterConnection(ContactId c, TransportId t, boolean incoming); Collection<ContactId> getConnectedContacts(TransportId t); diff --git a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java index 3c9f5fb48ed3d792a8180ae93bd5e8cc1e04e0eb..c85c5f016d64c3af085454ca856d240943f0b93f 100644 --- a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java +++ b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java @@ -144,7 +144,7 @@ class ConnectionManagerImpl implements ConnectionManager { return; } ContactId contactId = ctx.getContactId(); - connectionRegistry.registerConnection(contactId, transportId); + connectionRegistry.registerConnection(contactId, transportId, true); try { // Create and run the incoming session createIncomingSession(ctx, reader).run(); @@ -153,7 +153,8 @@ class ConnectionManagerImpl implements ConnectionManager { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); disposeReader(true, true); } finally { - connectionRegistry.unregisterConnection(contactId, transportId); + connectionRegistry.unregisterConnection(contactId, transportId, + true); } } @@ -194,7 +195,8 @@ class ConnectionManagerImpl implements ConnectionManager { disposeWriter(true); return; } - connectionRegistry.registerConnection(contactId, transportId); + connectionRegistry.registerConnection(contactId, transportId, + false); try { // Create and run the outgoing session createSimplexOutgoingSession(ctx, writer).run(); @@ -203,7 +205,8 @@ class ConnectionManagerImpl implements ConnectionManager { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); disposeWriter(true); } finally { - connectionRegistry.unregisterConnection(contactId, transportId); + connectionRegistry.unregisterConnection(contactId, transportId, + false); } } @@ -254,7 +257,7 @@ class ConnectionManagerImpl implements ConnectionManager { return; } contactId = ctx.getContactId(); - connectionRegistry.registerConnection(contactId, transportId); + connectionRegistry.registerConnection(contactId, transportId, true); // Start the outgoing session on another thread ioExecutor.execute(new Runnable() { public void run() { @@ -270,7 +273,8 @@ class ConnectionManagerImpl implements ConnectionManager { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); disposeReader(true, true); } finally { - connectionRegistry.unregisterConnection(contactId, transportId); + connectionRegistry.unregisterConnection(contactId, transportId, + true); } } @@ -398,7 +402,8 @@ class ConnectionManagerImpl implements ConnectionManager { disposeReader(true, true); return; } - connectionRegistry.registerConnection(contactId, transportId); + connectionRegistry.registerConnection(contactId, transportId, + false); try { // Create and run the incoming session incomingSession = createIncomingSession(ctx, reader); @@ -408,7 +413,8 @@ class ConnectionManagerImpl implements ConnectionManager { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); disposeReader(true, true); } finally { - connectionRegistry.unregisterConnection(contactId, transportId); + connectionRegistry.unregisterConnection(contactId, transportId, + false); } } diff --git a/briar-core/src/org/briarproject/plugins/ConnectionRegistryImpl.java b/briar-core/src/org/briarproject/plugins/ConnectionRegistryImpl.java index 0fe9c3b4b4cae11e0f407d61498acd62a89b9ff9..c7f726a985c9086ebbf11d90d1efd15e8b99df93 100644 --- a/briar-core/src/org/briarproject/plugins/ConnectionRegistryImpl.java +++ b/briar-core/src/org/briarproject/plugins/ConnectionRegistryImpl.java @@ -2,6 +2,8 @@ package org.briarproject.plugins; import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.event.ConnectionClosedEvent; +import org.briarproject.api.event.ConnectionOpenedEvent; import org.briarproject.api.event.ContactConnectedEvent; import org.briarproject.api.event.ContactDisconnectedEvent; import org.briarproject.api.event.EventBus; @@ -40,8 +42,12 @@ class ConnectionRegistryImpl implements ConnectionRegistry { contactCounts = new HashMap<ContactId, Integer>(); } - public void registerConnection(ContactId c, TransportId t) { - if (LOG.isLoggable(INFO)) LOG.info("Connection registered: " + t); + public void registerConnection(ContactId c, TransportId t, + boolean incoming) { + if (LOG.isLoggable(INFO)) { + if (incoming) LOG.info("Incoming connection registered: " + t); + else LOG.info("Outgoing connection registered: " + t); + } boolean firstConnection = false; lock.lock(); try { @@ -63,14 +69,19 @@ class ConnectionRegistryImpl implements ConnectionRegistry { } finally { lock.unlock(); } + eventBus.broadcast(new ConnectionOpenedEvent(c, t, incoming)); if (firstConnection) { LOG.info("Contact connected"); eventBus.broadcast(new ContactConnectedEvent(c)); } } - public void unregisterConnection(ContactId c, TransportId t) { - if (LOG.isLoggable(INFO)) LOG.info("Connection unregistered: " + t); + public void unregisterConnection(ContactId c, TransportId t, + boolean incoming) { + if (LOG.isLoggable(INFO)) { + if (incoming) LOG.info("Incoming connection unregistered: " + t); + else LOG.info("Outgoing connection unregistered: " + t); + } boolean lastConnection = false; lock.lock(); try { @@ -94,6 +105,7 @@ class ConnectionRegistryImpl implements ConnectionRegistry { } finally { lock.unlock(); } + eventBus.broadcast(new ConnectionClosedEvent(c, t, incoming)); if (lastConnection) { LOG.info("Contact disconnected"); eventBus.broadcast(new ContactDisconnectedEvent(c)); diff --git a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java index 4eb8da75b93907cb3e5ef1a03fbea07f9e74d21c..a03c23dbb547c845f3ea9b26b19dffdc29e6a9a8 100644 --- a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java +++ b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java @@ -3,6 +3,7 @@ package org.briarproject.plugins; import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DbException; +import org.briarproject.api.event.ConnectionClosedEvent; import org.briarproject.api.event.ContactStatusChangedEvent; import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; @@ -163,7 +164,16 @@ class PluginManagerImpl implements PluginManager, Service, EventListener { public void eventOccurred(Event e) { if (e instanceof ContactStatusChangedEvent) { ContactStatusChangedEvent c = (ContactStatusChangedEvent) e; - if (c.isActive()) connectToContact(c.getContactId()); + if (c.isActive()) { + // Connect to the newly activated contact + connectToContact(c.getContactId()); + } + } else if (e instanceof ConnectionClosedEvent) { + ConnectionClosedEvent c = (ConnectionClosedEvent) e; + if (!c.isIncoming()) { + // Connect to the disconnected contact + connectToContact(c.getContactId(), c.getTransportId()); + } } } @@ -174,6 +184,14 @@ class PluginManagerImpl implements PluginManager, Service, EventListener { if (d.shouldPoll()) connectToContact(c, d); } + private void connectToContact(ContactId c, TransportId t) { + Plugin p = plugins.get(t); + if (p instanceof SimplexPlugin && p.shouldPoll()) + connectToContact(c, (SimplexPlugin) p); + else if (p instanceof DuplexPlugin && p.shouldPoll()) + connectToContact(c, (DuplexPlugin) p); + } + private void connectToContact(final ContactId c, final SimplexPlugin p) { ioExecutor.execute(new Runnable() { public void run() { diff --git a/briar-tests/src/org/briarproject/plugins/ConnectionRegistryImplTest.java b/briar-tests/src/org/briarproject/plugins/ConnectionRegistryImplTest.java index 8ea235249bca696de2b2edc2323c5d9ecad2a3cc..b18634e0aa7db117d6ce634cf4d0f411bb5370bd 100644 --- a/briar-tests/src/org/briarproject/plugins/ConnectionRegistryImplTest.java +++ b/briar-tests/src/org/briarproject/plugins/ConnectionRegistryImplTest.java @@ -3,6 +3,8 @@ package org.briarproject.plugins; import org.briarproject.BriarTestCase; import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.event.ConnectionClosedEvent; +import org.briarproject.api.event.ConnectionOpenedEvent; import org.briarproject.api.event.ContactConnectedEvent; import org.briarproject.api.event.ContactDisconnectedEvent; import org.briarproject.api.event.EventBus; @@ -35,6 +37,10 @@ public class ConnectionRegistryImplTest extends BriarTestCase { Mockery context = new Mockery(); final EventBus eventBus = context.mock(EventBus.class); context.checking(new Expectations() {{ + exactly(5).of(eventBus).broadcast(with(any( + ConnectionOpenedEvent.class))); + exactly(2).of(eventBus).broadcast(with(any( + ConnectionClosedEvent.class))); exactly(3).of(eventBus).broadcast(with(any( ContactConnectedEvent.class))); oneOf(eventBus).broadcast(with(any( @@ -49,43 +55,46 @@ public class ConnectionRegistryImplTest extends BriarTestCase { assertEquals(Collections.emptyList(), c.getConnectedContacts(transportId1)); // Check that a registered connection shows up - this should - // broadcast a ContactConnectedEvent - c.registerConnection(contactId, transportId); + // broadcast a ConnectionOpenedEvent and a ContactConnectedEvent + c.registerConnection(contactId, transportId, true); assertEquals(Collections.singletonList(contactId), c.getConnectedContacts(transportId)); assertEquals(Collections.emptyList(), c.getConnectedContacts(transportId1)); - // Register an identical connection - lookup should be unaffected - c.registerConnection(contactId, transportId); + // Register an identical connection - this should broadcast a + // ConnectionOpenedEvent and lookup should be unaffected + c.registerConnection(contactId, transportId, true); assertEquals(Collections.singletonList(contactId), c.getConnectedContacts(transportId)); assertEquals(Collections.emptyList(), c.getConnectedContacts(transportId1)); - // Unregister one of the connections - lookup should be unaffected - c.unregisterConnection(contactId, transportId); + // Unregister one of the connections - this should broadcast a + // ConnectionClosedEvent and lookup should be unaffected + c.unregisterConnection(contactId, transportId, true); assertEquals(Collections.singletonList(contactId), c.getConnectedContacts(transportId)); assertEquals(Collections.emptyList(), c.getConnectedContacts(transportId1)); - // Unregister the other connection - lookup should be affected - - // this should broadcast a ContactDisconnectedEvent - c.unregisterConnection(contactId, transportId); + // Unregister the other connection - this should broadcast a + // ConnectionClosedEvent and a ContactDisconnectedEvent + c.unregisterConnection(contactId, transportId, true); assertEquals(Collections.emptyList(), c.getConnectedContacts(transportId)); assertEquals(Collections.emptyList(), c.getConnectedContacts(transportId1)); // Try to unregister the connection again - exception should be thrown try { - c.unregisterConnection(contactId, transportId); + c.unregisterConnection(contactId, transportId, true); fail(); } catch (IllegalArgumentException expected) { // Expected } // Register both contacts with one transport, one contact with both - - // this should broadcast two ContactConnectedEvents - c.registerConnection(contactId, transportId); - c.registerConnection(contactId1, transportId); - c.registerConnection(contactId1, transportId1); + // this should broadcast three ConnectionOpenedEvents and two + // ContactConnectedEvents + c.registerConnection(contactId, transportId, true); + c.registerConnection(contactId1, transportId, true); + c.registerConnection(contactId1, transportId1, true); Collection<ContactId> connected = c.getConnectedContacts(transportId); assertEquals(2, connected.size()); assertTrue(connected.contains(contactId));