package com.limegroup.gnutella; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.HashSet; import java.util.Set; import java.util.concurrent.TimeUnit; import org.limewire.core.settings.ConnectionSettings; import org.limewire.io.Address; import org.limewire.io.Connectable; import org.limewire.io.ConnectableImpl; import org.limewire.io.GUID; import org.limewire.listener.BlockingEventListener; import org.limewire.listener.ListenerSupport; import org.limewire.net.address.AddressEvent; import org.limewire.net.address.FirewalledAddress; import org.limewire.net.address.StrictIpPortSet; import org.limewire.rudp.RUDPUtils; import com.google.inject.AbstractModule; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Singleton; import com.limegroup.gnutella.util.LimeTestCase; public class NetworkManagerImplTest extends LimeTestCase { private Injector injector; private AddressChangedListener addressChangedListener; public NetworkManagerImplTest(String name) { super(name); } protected void setUp() throws Exception { super.setUp(); injector = LimeTestUtils.createInjectorAndStart(new AbstractModule() { @Override protected void configure() { //bind(ConnectionManager.class).toInstance(connectionManager); bind(AddressChangedListener.class); } }); addressChangedListener = injector.getInstance(AddressChangedListener.class); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); acceptor.setListeningPort(0); } protected void tearDown() { LifecycleManager lifecycleManager = injector.getInstance(LifecycleManager.class); lifecycleManager.shutdown(); } private void assertEquals(Connectable connectable, Address address) { assertEquals(connectable + "!=" + address, 0, ConnectableImpl.COMPARATOR.compare(connectable, (Connectable) address)); } public void testDirectConnectionAddressEvent() throws IOException { assertNull(addressChangedListener.getEvent()); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); acceptor.setExternalAddress(InetAddress.getByName(RemoteFileDesc.BOGUS_IP)); assertNull(addressChangedListener.getEvent()); acceptor.setExternalAddress(InetAddress.getByName("199.199.199.199")); assertNull(addressChangedListener.getEvent()); acceptor.setListeningPort(5000); assertNull(addressChangedListener.getEvent()); acceptor.setIncoming(true); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("199.199.199.199", 5000, true), event.getSource()); } public void testNewDirectConnectionAddressEventAcceptedIncomingTrigger() throws IOException { assertNull(addressChangedListener.getEvent()); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); acceptor.setExternalAddress(InetAddress.getByName("199.199.199.199")); acceptor.setListeningPort(5000); assertNull(addressChangedListener.getEvent()); acceptor.setIncoming(true); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("199.199.199.199", 5000, true), event.getSource()); } public void testNewDirectConnectionAddressEventExternalAddressTrigger() throws IOException { assertNull(addressChangedListener.getEvent()); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); acceptor.setIncoming(true); acceptor.setListeningPort(5000); assertNull(addressChangedListener.getEvent()); acceptor.setExternalAddress(InetAddress.getByName("199.199.199.199")); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("199.199.199.199", 5000, true), event.getSource()); } public void testNewDirectConnectionAddressEventPortTrigger() throws IOException { assertNull(addressChangedListener.getEvent()); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); acceptor.setIncoming(true); acceptor.setExternalAddress(InetAddress.getByName("199.199.199.199")); assertNull(addressChangedListener.getEvent()); acceptor.setListeningPort(5000); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("199.199.199.199", 5000, true), event.getSource()); } public void testDirectConnectionAddressEventNoDups() throws IOException { assertNull(addressChangedListener.getEvent()); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); acceptor.setExternalAddress(InetAddress.getByName("199.199.199.199")); acceptor.setListeningPort(5000); acceptor.setIncoming(true); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("199.199.199.199", 5000, true), event.getSource()); acceptor.setExternalAddress(InetAddress.getByName("199.199.199.199")); assertNull(addressChangedListener.getEvent()); acceptor.setListeningPort(5000); assertNull(addressChangedListener.getEvent()); acceptor.setIncoming(true); assertNull(addressChangedListener.getEvent()); } public void testDirectConnectionAddressEventTriggeredAfterAllInfoIsThere() throws IOException { assertNull(addressChangedListener.getEvent()); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); acceptor.setExternalAddress(InetAddress.getByAddress(new byte[] { (byte)129, 0, 0, 1 })); assertNull(addressChangedListener.getEvent()); acceptor.setListeningPort(5000); assertNull(addressChangedListener.getEvent()); acceptor.setIncoming(true); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("129.0.0.1", 5000, true), event.getSource()); } public void testDirectConnectionAddressChangedExternalAddressTrigger() throws IOException { assertNull(addressChangedListener.getEvent()); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); acceptor.setExternalAddress(InetAddress.getByName("199.199.199.199")); acceptor.setListeningPort(5000); acceptor.setIncoming(true); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("199.199.199.199", 5000, true), event.getSource()); acceptor.setExternalAddress(InetAddress.getByName("200.200.200.200")); event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("200.200.200.200", 5000, true), event.getSource()); } public void testDirectConnectionAddressChangedEventPortTrigger() throws IOException { assertNull(addressChangedListener.getEvent()); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); acceptor.setExternalAddress(InetAddress.getByName("199.199.199.199")); acceptor.setListeningPort(5000); acceptor.setIncoming(true); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("199.199.199.199", 5000, true), event.getSource()); acceptor.setListeningPort(5001); event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("199.199.199.199", 5001, true), event.getSource()); } public void testDirectConnectionAddressSupressesPushProxyAddressEvent() throws IOException { assertNull(addressChangedListener.getEvent()); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); acceptor.setExternalAddress(InetAddress.getByAddress(new byte[] { (byte)129, 0, 0, 1 })); acceptor.setListeningPort(5000); acceptor.setIncoming(true); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(new ConnectableImpl("129.0.0.1", 5000, true), event.getSource()); NetworkManager networkManager = injector.getInstance(NetworkManager.class); assertNull(addressChangedListener.getEvent()); Set<Connectable> proxies = new StrictIpPortSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); networkManager.newPushProxies(proxies); assertNull(addressChangedListener.getEvent()); } public void testPushProxyAddressEvent() throws IOException { ApplicationServices applicationServices = injector.getInstance(ApplicationServices.class); NetworkManager networkManager = injector.getInstance(NetworkManager.class); AcceptorImpl acceptor = (AcceptorImpl) injector.getInstance(Acceptor.class); assertNull(addressChangedListener.getEvent()); acceptor.setListeningPort(5000); acceptor.setExternalAddress(InetAddress.getByName("129.0.0.1")); Set<Connectable> proxies = new StrictIpPortSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); networkManager.newPushProxies(proxies); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); FirewalledAddress firewalledAddress = (FirewalledAddress)event.getSource(); assertEquals(proxies, firewalledAddress.getPushProxies()); assertEquals(applicationServices.getMyGUID(), firewalledAddress.getClientGuid().bytes()); } public void testPushProxyAddressChangedEvent() throws IOException { ApplicationServices applicationServices = injector.getInstance(ApplicationServices.class); NetworkManager networkManager = injector.getInstance(NetworkManager.class); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); // regular setup which usually takes place before first push proxies come in acceptor.setListeningPort(5000); acceptor.setExternalAddress(InetAddress.getByName("129.0.0.1")); assertNull(addressChangedListener.getEvent()); Set<Connectable> proxies = new StrictIpPortSet<Connectable>(); networkManager.newPushProxies(proxies); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); FirewalledAddress firewalledAddress = (FirewalledAddress)event.getSource(); assertEquals(proxies, firewalledAddress.getPushProxies()); assertEquals(applicationServices.getMyGUID(), firewalledAddress.getClientGuid().bytes()); proxies = new StrictIpPortSet<Connectable>(); Connectable proxyAddress = new ConnectableImpl("199.199.199.199", 5000, true); Connectable proxyAddress2 = new ConnectableImpl("200.200.200.200", 5001, false); proxies.add(proxyAddress); proxies.add(proxyAddress2); networkManager.newPushProxies(proxies); event = addressChangedListener.getEvent(); assertNotNull(event); firewalledAddress = (FirewalledAddress)event.getSource(); assertEquals(proxies, firewalledAddress.getPushProxies()); assertEquals(applicationServices.getMyGUID(), firewalledAddress.getClientGuid().bytes()); } public void testPushProxyAddressEventNoDups() throws IOException { ApplicationServices applicationServices = injector.getInstance(ApplicationServices.class); NetworkManager networkManager = injector.getInstance(NetworkManager.class); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); // regular setup which usually takes place before first push proxies come in acceptor.setListeningPort(5000); acceptor.setExternalAddress(InetAddress.getByName("129.0.0.1")); assertNull(addressChangedListener.getEvent()); Set<Connectable> proxies = new StrictIpPortSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); networkManager.newPushProxies(proxies); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); FirewalledAddress firewalledAddress = (FirewalledAddress)event.getSource(); assertEquals(proxies, firewalledAddress.getPushProxies()); assertEquals(applicationServices.getMyGUID(), firewalledAddress.getClientGuid().bytes()); proxies = new StrictIpPortSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); networkManager.newPushProxies(proxies); assertNull(addressChangedListener.getEvent()); } public void testNewPushProxyHolePunchAddressEventFWTStatusTrigger() throws IOException { ApplicationServices applicationServices = injector.getInstance(ApplicationServices.class); NetworkManager networkManager = injector.getInstance(NetworkManager.class); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); // regular setup which usually takes place before first push proxies come in acceptor.setListeningPort(5000); acceptor.setExternalAddress(InetAddress.getByName("129.0.0.1")); assertNull(addressChangedListener.getEvent()); Set<Connectable> proxies = new StrictIpPortSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); networkManager.newPushProxies(proxies); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); FirewalledAddress firewalledAddress = (FirewalledAddress)event.getSource(); assertEquals(proxies, firewalledAddress.getPushProxies()); assertEquals(applicationServices.getMyGUID(), firewalledAddress.getClientGuid().bytes()); assertEquals(0, firewalledAddress.getFwtVersion()); // set valid external address and port for proper fwt support acceptor.setExternalAddress(InetAddress.getByName("200.200.200.200")); acceptor.setListeningPort(5001); // signal fwt capability UDPService udpService = injector.getInstance(UDPService.class); udpService.setReceiveSolicited(true); ConnectionSettings.CANNOT_DO_FWT.setValue(false); networkManager.incomingStatusChanged(); event = addressChangedListener.getEvent(); assertNotNull(event); acceptor.setExternalAddress(InetAddress.getByName("100.100.100.100")); acceptor.setListeningPort(5001); networkManager.incomingStatusChanged(); event = addressChangedListener.getEvent(); assertNotNull(event); firewalledAddress = (FirewalledAddress)event.getSource(); assertEquals(proxies, firewalledAddress.getPushProxies()); assertEquals(applicationServices.getMyGUID(), firewalledAddress.getClientGuid().bytes()); assertEquals(RUDPUtils.VERSION, firewalledAddress.getFwtVersion()); assertEquals(new ConnectableImpl("100.100.100.100", 5001, true), firewalledAddress.getPublicAddress()); } public void testNewPushProxyHolePunchAddressEventPushProxyTrigger() throws IOException { ApplicationServices applicationServices = injector.getInstance(ApplicationServices.class); NetworkManager networkManager = injector.getInstance(NetworkManager.class); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); assertNull(addressChangedListener.getEvent()); UDPService udpService = injector.getInstance(UDPService.class); udpService.setReceiveSolicited(true); ConnectionSettings.CANNOT_DO_FWT.setValue(false); networkManager.incomingStatusChanged(); assertNull(addressChangedListener.getEvent()); acceptor.setExternalAddress(InetAddress.getByName("200.200.200.200")); InetAddress privateAddress = InetAddress.getByName("192.168.0.1"); acceptor.setAddress(privateAddress); acceptor.setListeningPort(5001); Set<Connectable> proxies = new StrictIpPortSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); networkManager.newPushProxies(proxies); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); FirewalledAddress expectedAddress = new FirewalledAddress(new ConnectableImpl("200.200.200.200", 5001, true), new ConnectableImpl(new InetSocketAddress(privateAddress, 5001), networkManager.isIncomingTLSEnabled()), new GUID(applicationServices.getMyGUID()), proxies, networkManager.supportsFWTVersion()); assertEquals(expectedAddress, event.getSource()); } public void testPushProxyHolePunchAddressChangedEventPushProxyTrigger() throws IOException { ApplicationServices applicationServices = injector.getInstance(ApplicationServices.class); NetworkManager networkManager = injector.getInstance(NetworkManager.class); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); assertNull(addressChangedListener.getEvent()); UDPService udpService = injector.getInstance(UDPService.class); udpService.setReceiveSolicited(true); ConnectionSettings.CANNOT_DO_FWT.setValue(false); InetAddress privateAddress = InetAddress.getByName("192.168.0.1"); acceptor.setAddress(privateAddress); acceptor.setExternalAddress(InetAddress.getByName("200.200.200.200")); acceptor.setListeningPort(5001); Set<Connectable> proxies = new StrictIpPortSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); networkManager.newPushProxies(proxies); FirewalledAddress expectedAddress = new FirewalledAddress(new ConnectableImpl("200.200.200.200", 5001, true), new ConnectableImpl(new InetSocketAddress(privateAddress, networkManager.getNonForcedPort()), networkManager.isIncomingTLSEnabled()), new GUID(applicationServices.getMyGUID()), proxies, networkManager.supportsFWTVersion()); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(expectedAddress, event.getSource()); proxies = new StrictIpPortSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); proxies.add(new ConnectableImpl("201.201.201.201", 5002, false)); networkManager.newPushProxies(proxies); expectedAddress = new FirewalledAddress(new ConnectableImpl("200.200.200.200", 5001, true), new ConnectableImpl(new InetSocketAddress(privateAddress, networkManager.getNonForcedPort()), networkManager.isIncomingTLSEnabled()), new GUID(applicationServices.getMyGUID()), proxies, networkManager.supportsFWTVersion()); event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(expectedAddress, event.getSource()); } public void testPushProxyHolePunchAddressChangedEventFWTStatusTrigger() throws IOException { ApplicationServices applicationServices = injector.getInstance(ApplicationServices.class); NetworkManager networkManager = injector.getInstance(NetworkManager.class); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); assertNull(addressChangedListener.getEvent()); UDPService udpService = injector.getInstance(UDPService.class); udpService.setReceiveSolicited(true); ConnectionSettings.CANNOT_DO_FWT.setValue(false); InetAddress privateAddress = InetAddress.getByName("192.168.0.1"); acceptor.setAddress(privateAddress); acceptor.setExternalAddress(InetAddress.getByName("200.200.200.200")); acceptor.setListeningPort(5001); Set<Connectable> proxies = new HashSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); networkManager.newPushProxies(proxies); FirewalledAddress expectedAddress = new FirewalledAddress(new ConnectableImpl("200.200.200.200", 5001, true), new ConnectableImpl(new InetSocketAddress(privateAddress, networkManager.getNonForcedPort()), networkManager.isIncomingTLSEnabled()), new GUID(applicationServices.getMyGUID()), proxies, networkManager.supportsFWTVersion()); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(expectedAddress, event.getSource()); udpService.setReceiveSolicited(false); ConnectionSettings.CANNOT_DO_FWT.setValue(false); networkManager.incomingStatusChanged(); expectedAddress = new FirewalledAddress(new ConnectableImpl("200.200.200.200", 5001, true), new ConnectableImpl(new InetSocketAddress(privateAddress, networkManager.getNonForcedPort()), networkManager.isIncomingTLSEnabled()), new GUID(applicationServices.getMyGUID()), proxies, networkManager.supportsFWTVersion()); event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(expectedAddress, event.getSource()); } public void testPushProxyHolePunchAddressEventNoDups() throws IOException { ApplicationServices applicationServices = injector.getInstance(ApplicationServices.class); NetworkManager networkManager = injector.getInstance(NetworkManager.class); AcceptorImpl acceptor = (AcceptorImpl)injector.getInstance(Acceptor.class); assertNull(addressChangedListener.getEvent()); UDPService udpService = injector.getInstance(UDPService.class); udpService.setReceiveSolicited(true); ConnectionSettings.CANNOT_DO_FWT.setValue(false); InetAddress privateAddress = InetAddress.getByName("192.168.0.1"); acceptor.setAddress(privateAddress); acceptor.setExternalAddress(InetAddress.getByName("200.200.200.200")); acceptor.setListeningPort(5001); Set<Connectable> proxies = new StrictIpPortSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); networkManager.newPushProxies(proxies); FirewalledAddress expectedAddress = new FirewalledAddress(new ConnectableImpl("200.200.200.200", 5001, true), new ConnectableImpl(new InetSocketAddress(privateAddress, networkManager.getNonForcedPort()), networkManager.isIncomingTLSEnabled()), new GUID(applicationServices.getMyGUID()), proxies, networkManager.supportsFWTVersion()); AddressEvent event = addressChangedListener.getEvent(); assertNotNull(event); assertEquals(expectedAddress, event.getSource()); networkManager.incomingStatusChanged(); assertNull(addressChangedListener.getEvent()); proxies = new StrictIpPortSet<Connectable>(); proxies.add(new ConnectableImpl("199.199.199.199", 5000, true)); networkManager.newPushProxies(proxies); assertNull(addressChangedListener.getEvent()); } public void testNewPushProxiesDoesNotTriggerEventIfExternalAddressNotKnownYet() throws Exception { NetworkManager networkManager = injector.getInstance(NetworkManager.class); Acceptor acceptor = injector.getInstance(Acceptor.class); acceptor.setListeningPort(5000); // no events, since no valid address yet assertNull(addressChangedListener.getEvent()); networkManager.newPushProxies(new StrictIpPortSet<Connectable>(new ConnectableImpl("129.0.0.1", 4545, true))); // no events, since no valid address yet assertNull(addressChangedListener.getEvent()); // now set external address and test for events again acceptor.setExternalAddress(InetAddress.getByName("199.0.0.1")); AddressEvent event = addressChangedListener.getEvent(); FirewalledAddress address = (FirewalledAddress) event.getSource(); assertEquals(new ConnectableImpl("199.0.0.1", 5000, true), address.getPublicAddress()); assertEquals(new StrictIpPortSet<Connectable>(new ConnectableImpl("129.0.0.1", 4545, true)), address.getPushProxies()); } @Singleton public static class AddressChangedListener extends BlockingEventListener<AddressEvent> { @Inject void register(ListenerSupport<AddressEvent> broadcaster) { broadcaster.addListener(this); } AddressEvent getEvent() { return getEvent(25, TimeUnit.MILLISECONDS); } } }