package com.limegroup.gnutella.messagehandlers; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Random; import java.util.Set; import junit.framework.Test; import org.limewire.core.settings.MessageSettings; import org.limewire.core.settings.SearchSettings; import org.limewire.gnutella.tests.LimeTestUtils; import org.limewire.gnutella.tests.NetworkManagerStub; import org.limewire.io.GUID; import org.limewire.io.IpPort; import org.limewire.security.AddressSecurityToken; import org.limewire.security.InvalidSecurityTokenException; import org.limewire.security.MACCalculatorRepositoryManager; import org.limewire.security.SecurityToken; import org.limewire.util.BaseTestCase; import com.google.inject.AbstractModule; import com.google.inject.Injector; import com.google.inject.Module; import com.limegroup.gnutella.MessageListener; import com.limegroup.gnutella.MessageRouter; import com.limegroup.gnutella.ReplyHandler; import com.limegroup.gnutella.Response; import com.limegroup.gnutella.ResponseFactory; import com.limegroup.gnutella.URN; import com.limegroup.gnutella.connection.RoutedConnection; import com.limegroup.gnutella.filters.SpamFilter; import com.limegroup.gnutella.guess.GUESSEndpoint; import com.limegroup.gnutella.messages.Message; import com.limegroup.gnutella.messages.PingRequest; import com.limegroup.gnutella.messages.PushRequest; import com.limegroup.gnutella.messages.QueryReply; import com.limegroup.gnutella.messages.QueryReplyFactory; import com.limegroup.gnutella.messages.QueryRequest; import com.limegroup.gnutella.messages.vendor.InspectionRequest; import com.limegroup.gnutella.messages.vendor.LimeACKVendorMessage; import com.limegroup.gnutella.messages.vendor.ReplyNumberVendorMessage; import com.limegroup.gnutella.messages.vendor.ReplyNumberVendorMessageFactory; import com.limegroup.gnutella.messages.vendor.ReplyNumberVendorMessageFactoryImpl; import com.limegroup.gnutella.routing.QueryRouteTable; import com.limegroup.gnutella.stubs.ReplyHandlerStub; public class OOBHandlerTest extends BaseTestCase { public OOBHandlerTest(String name) { super(name); } public static Test suite() { return buildTestSuite(OOBHandlerTest.class); } private Random random = new Random(); private MyMessageRouter router; private OOBHandler handler; private GUID g; private InetAddress address; private MyReplyHandler replyHandler; private ReplyNumberVendorMessageFactory factory; private MACCalculatorRepositoryManager macManager; private volatile boolean canReceiveUnsolicited; ResponseFactory responseFactory; QueryReplyFactory queryReplyFactory; @Override public void setUp() throws Exception { router = new MyMessageRouter(); router.start(); macManager = new MACCalculatorRepositoryManager(); g = new GUID(GUID.makeGuid()); address = InetAddress.getByName("1.2.3.4"); replyHandler = new MyReplyHandler(address, 1); canReceiveUnsolicited = false; factory = new ReplyNumberVendorMessageFactoryImpl(new NetworkManagerStub() { @Override public boolean canReceiveUnsolicited() { return canReceiveUnsolicited; } }); Module module = new AbstractModule() { @Override protected void configure() { bind(ReplyNumberVendorMessageFactory.class).toInstance(factory); bind(MessageRouter.class).toInstance(router); bind(MACCalculatorRepositoryManager.class).toInstance(macManager); } }; Injector injector = LimeTestUtils.createInjectorNonEagerly(module); responseFactory = injector.getInstance(ResponseFactory.class); queryReplyFactory = injector.getInstance(QueryReplyFactory.class); handler = injector.getInstance(OOBHandler.class); } public void testRedundantAcks() throws Exception { MessageSettings.OOB_REDUNDANCY.setValue(true); // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); assertNotNull(replyHandler.m); assertTrue(replyHandler.m instanceof LimeACKVendorMessage); LimeACKVendorMessage ack = (LimeACKVendorMessage) replyHandler.m; assertEquals(10, ack.getNumResults()); assertNotNull(ack.getSecurityToken()); // 100 ms later a second ack should be sent replyHandler.m = null; Thread.sleep(120); assertSame(ack, replyHandler.m); } public void testNoRedundantAcks() throws Exception { MessageSettings.OOB_REDUNDANCY.setValue(false); // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); assertNotNull(replyHandler.m); assertTrue(replyHandler.m instanceof LimeACKVendorMessage); LimeACKVendorMessage ack = (LimeACKVendorMessage) replyHandler.m; assertEquals(10, ack.getNumResults()); assertNotNull(ack.getSecurityToken()); // no more acks replyHandler.m = null; Thread.sleep(120); assertNull(replyHandler.m); } public void testDuplicateRNVMs() throws Exception { MessageSettings.OOB_REDUNDANCY.setValue(false); // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); assertNotNull(replyHandler.m); assertTrue(replyHandler.m instanceof LimeACKVendorMessage); LimeACKVendorMessage ack = (LimeACKVendorMessage) replyHandler.m; assertEquals(10, ack.getNumResults()); assertNotNull(ack.getSecurityToken()); replyHandler.m = null; // a duplicate RNVM arrives handler.handleMessage(rnvm, null, replyHandler); // but we don't send an ack assertNull(replyHandler.m); // ever replyHandler.m = null; Thread.sleep(50); handler.handleMessage(rnvm, null, replyHandler); assertNull(replyHandler.m); Thread.sleep(50); handler.handleMessage(rnvm, null, replyHandler); assertNull(replyHandler.m); } /** * tests that duplicate RNVMs will send only the correct # of acks */ public void testDuplicateRNVMsRedundantACKs() throws Exception { MessageSettings.OOB_REDUNDANCY.setValue(true); // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); assertNotNull(replyHandler.m); assertTrue(replyHandler.m instanceof LimeACKVendorMessage); LimeACKVendorMessage ack = (LimeACKVendorMessage) replyHandler.m; assertEquals(10, ack.getNumResults()); assertNotNull(ack.getSecurityToken()); replyHandler.m = null; // a duplicate RNVM arrives handler.handleMessage(rnvm, null, replyHandler); // but we don't send an ack assertNull(replyHandler.m); // a little later another duplicate RNVM arrives // we don't ack Thread.sleep(50); handler.handleMessage(rnvm, null, replyHandler); assertNull(replyHandler.m); // after a while the redundancy interval hits and we send the // redundant ACK Thread.sleep(70); assertSame(ack, replyHandler.m); // any further RNVMs do nothing replyHandler.m = null; Thread.sleep(50); handler.handleMessage(rnvm, null, replyHandler); assertNull(replyHandler.m); Thread.sleep(50); handler.handleMessage(rnvm, null, replyHandler); assertNull(replyHandler.m); } public void testDropsLargeResponses() throws Exception { // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); // and we request all of them router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); SecurityToken token = assertACKSent(replyHandler, 10); // first send back only 8 results - those should be accepted QueryReply reply = getReplyWithResults(g.bytes(), 8, address .getAddress(), token); handler.handleMessage(reply, null, replyHandler); assertSame(reply, router.reply); // then send back 4 more results - those should not be accepted. router.reply = null; reply = getReplyWithResults(g.bytes(), 4, address.getAddress(), token); handler.handleMessage(reply, null, replyHandler); assertNull(router.reply); } public void testMessagesWithoutEchoedTokenAreDiscardedForDisabledOOBV2() { SearchSettings.DISABLE_OOB_V2.setBoolean(true); testMessagesWithoutEchoedTokenAreHandled(true); } public void testMessagesWithoutEchoedTokenAreNotDiscardedForEnabledOOBV2() { SearchSettings.DISABLE_OOB_V2.setBoolean(false); testMessagesWithoutEchoedTokenAreHandled(false); } public void testMessagesWithoutEchoedTokenAreHandled(boolean disableOOBV2) { // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); // and we request all of them router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); assertACKSent(replyHandler, 10); // first send back only 10 results without token - those should be // discarded QueryReply reply = getReplyWithResults(g.bytes(), 10, address .getAddress(), null); router.reply = null; handler.handleMessage(reply, null, replyHandler); if (disableOOBV2) { assertNotSame(reply, router.reply); } else { assertSame(reply, router.reply); } } public void testMessagesWithInvalidTokenAreDiscardedForDisabledOOBV2() throws Exception { SearchSettings.DISABLE_OOB_V2.setBoolean(true); testMessagesWithDifferentTokenAreHandled(true); } public void testMessagesWithInvalidTokenAreDiscardedForEnabledOOBV2() throws Exception { SearchSettings.DISABLE_OOB_V2.setBoolean(false); testMessagesWithDifferentTokenAreHandled(false); } public void testMessagesWithDifferentTokenAreHandled(boolean disableOOBV2) throws InvalidSecurityTokenException { // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); // and we request all of them router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); assertACKSent(replyHandler, 10); byte[] bytes = new byte[8]; random.nextBytes(bytes); SecurityToken tokenFake = new AddressSecurityToken(bytes, macManager); // send back messages with fake token QueryReply reply = getReplyWithResults(g.bytes(), 10, address .getAddress(), tokenFake); router.reply = null; handler.handleMessage(reply, null, replyHandler); assertNull(router.reply); } public void testDropsUnAckedForDisabledOOBV2() throws Exception { SearchSettings.DISABLE_OOB_V2.setBoolean(true); testHandlesUnAcked(true); } public void testAcceptsUnAckedForEnabledOOBV2() throws Exception { SearchSettings.DISABLE_OOB_V2.setBoolean(false); testHandlesUnAcked(false); } public void testHandlesUnAcked(boolean disableOOBV2) throws Exception { // send some results w/o an RNVM QueryReply reply = getReplyWithResults(g.bytes(), 10, address .getAddress(), null); router.reply = null; handler.handleMessage(reply, null, replyHandler); if (disableOOBV2) { // should be ignored. assertNull(router.reply); } else { assertSame(reply, router.reply); } // send an RNVM now ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); // double check we sent back an ack SecurityToken token = assertACKSent(replyHandler, 10); // and resend the almost same results reply = getReplyWithResults(g.bytes(), 5, address.getAddress(), token); handler.handleMessage(reply, null, replyHandler); // they should be forwarded to the router now assertSame(reply, router.reply); } public void testResultsIgnoredWhenSessionIsFull() throws Exception { // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); // double check we sent back an ack SecurityToken token = assertACKSent(replyHandler, 10); // send some results router.reply = null; QueryReply reply = getReplyWithResults(g.bytes(), 5, address.getAddress(), token); handler.handleMessage(reply, null, replyHandler); assertNotNull(router.reply); // and some more router.reply = null; reply = getReplyWithResults(g.bytes(), 5, address.getAddress(), token, 5); handler.handleMessage(reply, null, replyHandler); assertNotNull(router.reply); // further results should be ignored since the session is full router.reply = null; reply = getReplyWithResults(g.bytes(), 5, address.getAddress(), token, 10); handler.handleMessage(reply, null, replyHandler); assertNull(router.reply); } public void testResultsIgnoredWhenQueryIsDead() throws Exception { // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); // double check we sent back an ack SecurityToken token = assertACKSent(replyHandler, 10); // send some results router.reply = null; QueryReply reply = getReplyWithResults(g.bytes(), 5, address.getAddress(), token); handler.handleMessage(reply, null, replyHandler); assertNotNull(router.reply); // eventually the query dies router.isAlive = false; // further results should be ignored since the query is dead router.reply = null; reply = getReplyWithResults(g.bytes(), 5, address.getAddress(), token, 5); handler.handleMessage(reply, null, replyHandler); assertNull(router.reply); } public void testQueryIsAliveOverridesSessionTimeout() throws InterruptedException { router.isAlive = true; router.timeToExpire = 50; router.reply = null; // send reply number message ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); // double check we sent back an ack SecurityToken token = assertACKSent(replyHandler, 10); router.reply = null; QueryReply reply = getReplyWithResults(g.bytes(), 8, address .getAddress(), token); handler.handleMessage(reply, null, replyHandler); assertSame(reply, router.reply); router.reply = null; reply = getReplyWithResults(g.bytes(), 4, address.getAddress(), token, 8); handler.handleMessage(reply, null, replyHandler); assertNull(router.reply); // run timeout, but should be still discarded, since query is alive Thread.sleep(100); handler.run(); handler.handleMessage(reply, null, replyHandler); assertNull(router.reply); } public void testAddsRNVMs() throws Exception { // a host claims to have 10 results at first ReplyNumberVendorMessage first = factory.create(g, 10); // and then 20 afterwards ReplyNumberVendorMessage second = factory.create(g, 10); // we would like to get 10 router.numToRequest = 10; // first we receive the message saying they have 10 handler.handleMessage(first, null, replyHandler); // we sould respond we want them SecurityToken token1 = assertACKSent(replyHandler, 10); // then we receive the second rnvm and want only 15/20 replyHandler.m = null; router.numToRequest = 5; handler.handleMessage(second, null, replyHandler); SecurityToken token2 = assertACKSent(replyHandler, 5); // if we get back a reply with 25 results we should accept it. QueryReply reply = getReplyWithResults(g.bytes(), 10, address .getAddress(), token1); handler.handleMessage(reply, null, replyHandler); assertSame(reply, router.reply); reply = getReplyWithResults(g.bytes(), 5, address.getAddress(), token2, 10); handler.handleMessage(reply, null, replyHandler); assertSame(reply, router.reply); } public void testDiscardedWithoutAliveQuery() throws InterruptedException { // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); // double check we sent back an ack SecurityToken token = assertACKSent(replyHandler, 10); // send reply, only then session objects are created QueryReply reply = getReplyWithResults(g.bytes(), 5, address .getAddress(), token); handler.handleMessage(reply, null, replyHandler); assertNotNull(router.reply); router.reply = null; try { router.isAlive = false; handler.handleMessage(reply, null, replyHandler); // should be ignored. assertNull(router.reply); } finally { router.isAlive = true; } // send 5 other ones, marked by new offset again, now that search is // alive again reply = getReplyWithResults(g.bytes(), 5, address.getAddress(), token, 5); handler.handleMessage(reply, null, replyHandler); assertSame(reply, router.reply); // and now send the old ones again after expiration that does nothing handler.run(); router.reply = null; handler.handleMessage(reply, null, replyHandler); assertNull(router.reply); } public void testDuplicatePacketsIgnored() { // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); // double check we sent back an ack SecurityToken token = assertACKSent(replyHandler, 10); // send reply, only then session objects are created QueryReply reply = getReplyWithResults(g.bytes(), 5, address .getAddress(), token); handler.handleMessage(reply, null, replyHandler); assertNotNull(router.reply); router.reply = null; // send same five and message should be discarded handler.handleMessage(reply, null, replyHandler); assertNull(router.reply); } public void testStoresBypassedResultsNoRouteBack() throws Exception { // set this for this test canReceiveUnsolicited = true; // 1. case there's no route back GUID guid = new GUID(); ReplyNumberVendorMessage rnvm = factory.create(guid, 10); assertTrue(rnvm.canReceiveUnsolicited()); router.numToRequest = 10; router.isAlive = false; router.reply = null; handler.handleMessage(rnvm, null, replyHandler); assertNull(router.reply); assertSame(rnvm, router.bypassedReply); } public void testStoresBypassedResultsEnoughResultsReceived() throws Exception { // set this for this test canReceiveUnsolicited = true; // 2. case we received enough results, i.e, it's more than 150 results GUID guid = new GUID(); ReplyNumberVendorMessage rnvm = factory.create(guid, 10); assertTrue(rnvm.canReceiveUnsolicited()); router.numToRequest = -1; // signals enough results have been received router.isAlive = true; router.reply = null; handler.handleMessage(rnvm, null, replyHandler); assertNull(router.reply); assertSame(rnvm, router.bypassedReply); } public void testStoresBypassedResultsFirstQueryReplyButQueryDead() throws Exception { // set this for this test canReceiveUnsolicited = true; // 3. case the first query reply comes in but the query is not alive GUID guid = new GUID(); ReplyNumberVendorMessage rnvm = factory.create(guid, 10); router.numToRequest = 10; router.isAlive = true; router.reply = null; handler.handleMessage(rnvm, null, replyHandler); // source is not remembered yet assertNull(router.bypassedReply); // double check we sent back an ack SecurityToken token = assertACKSent(replyHandler, 10); // send reply, only then session objects are created QueryReply reply = getReplyWithResults(guid.bytes(), 10, address .getAddress(), token); // timeout query router.isAlive = false; try { // send same five and message should be discarded handler.handleMessage(reply, null, replyHandler); assertNull(router.reply); assertSame(reply, router.bypassedQueryReply); } finally { router.isAlive = true; } } /** * Tests if the ip address of a query reply is overwritten with the address * from the reply handler if they don't match. */ public void testMismatchingPublicAddressIsOverwritten() throws Exception { // a host claims to have 10 results ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); // double check we sent back an ack SecurityToken token = assertACKSent(replyHandler, 10); // use different non-private address in reply QueryReply reply = getReplyWithResults(g.bytes(), 10, new byte[] { (byte)129, (byte) 168, 0, 5}, token); assertNotEquals(replyHandler.getInetAddress().getAddress(), reply.getIPBytes()); assertFalse(reply.getNeedsPush()); router.reply = null; handler.handleMessage(reply, null, replyHandler); assertNotNull(router.reply); QueryReply handled = router.reply; assertEquals(replyHandler.getInetAddress().getAddress(), handled.getIPBytes()); } /** * Test case where ip is private, but needs push. */ public void testMismatchingPrivateAddressIsOverwrittenForNeedsPush() throws Exception { router.numToRequest = 10; handler.handleMessage(factory.create(g, 10), null, replyHandler); SecurityToken token = assertACKSent(replyHandler, 10); QueryReply reply = getReplyWithResults(g.bytes(), 10, new byte[] { (byte)192, (byte) 168, 0, 5}, token, true); assertNotEquals(replyHandler.getInetAddress().getAddress(), reply.getIPBytes()); assertTrue(reply.getNeedsPush()); router.reply = null; handler.handleMessage(reply, null, replyHandler); assertNotNull(router.reply); QueryReply handled = router.reply; assertEquals(replyHandler.getInetAddress().getAddress(), handled.getIPBytes()); } /** * Case were ip is private and no need for push indicated, should not change address. */ public void testMismatchingPrivateAddressIsNotOverwrittenForNoPush() throws Exception { router.numToRequest = 10; handler.handleMessage(factory.create(g, 10), null, replyHandler); SecurityToken token = assertACKSent(replyHandler, 10); QueryReply reply = getReplyWithResults(g.bytes(), 10, new byte[] { (byte)192, (byte) 168, 0, 5}, token, false); assertNotEquals(replyHandler.getInetAddress().getAddress(), reply.getIPBytes()); assertFalse(reply.getNeedsPush()); router.reply = null; handler.handleMessage(reply, null, replyHandler); assertNotNull(router.reply); QueryReply handled = router.reply; assertNotEquals(replyHandler.getInetAddress().getAddress(), handled.getIPBytes()); assertEquals(new byte[] { (byte)192, (byte) 168, 0, 5 }, handled.getIPBytes()); } /** * Tests that the mismatching address of v2 replies is overwritten. */ public void testOOBv2MismatchingPublicAddressIsOverwritten() throws Exception { ReplyNumberVendorMessage rnvm = factory.createV2ReplyNumberVendorMessage(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); QueryReply reply = getReplyWithResults(g.bytes(), 10, new byte[] { (byte)129, (byte) 168, 0, 5}, null); assertNotEquals(replyHandler.getInetAddress().getAddress(), reply.getIPBytes()); router.reply = null; handler.handleMessage(reply, null, replyHandler); assertNotNull(router.reply); QueryReply handled = router.reply; assertEquals(replyHandler.getInetAddress().getAddress(), handled.getIPBytes()); } /** * Tests that if two RNVMs are received from the same address but * different ports, the address is ignored */ public void testMultiplePortsCauseAddressToBeIgnored() throws Exception { InetAddress addr1 = InetAddress.getByName("1.2.3.4"); InetAddress addr2 = InetAddress.getByName("2.3.4.5"); int port1 = 1234, port2 = 2345; // RNVM from addr1:port1 should be acked ReplyNumberVendorMessage rnvm = factory.create(g, 10); replyHandler = new MyReplyHandler(addr1, port1); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); assertACKSent(replyHandler, 10); // RNVM from addr1:port2 should be ignored rnvm = factory.create(g, 10); replyHandler = new MyReplyHandler(addr1, port2); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); assertNull(replyHandler.m); // RNVM from addr1:port1 should now be ignored as well rnvm = factory.create(g, 10); replyHandler = new MyReplyHandler(addr1, port1); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); assertNull(replyHandler.m); // RNVM from addr2:port2 should be acked rnvm = factory.create(g, 10); replyHandler = new MyReplyHandler(addr2, port2); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler); assertACKSent(replyHandler, 10); } /** * Tests that if too many results are received from an address, * subsequent RNVMs from that address are ignored */ public void testTooManyResultsCauseAddressToBeIgnored() throws Exception { InetAddress addr1 = InetAddress.getByName("1.2.3.4"); InetAddress addr2 = InetAddress.getByName("2.3.4.5"); int port1 = 1234, port2 = 2345; MyReplyHandler replyHandler1 = new MyReplyHandler(addr1, port1); MyReplyHandler replyHandler2 = new MyReplyHandler(addr2, port2); // RNVM from addr1 should be acked ReplyNumberVendorMessage rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler1); SecurityToken token1 = assertACKSent(replyHandler1, 10); // RNVM from addr2 should be acked rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler2); SecurityToken token2 = assertACKSent(replyHandler2, 10); // Replies from addr1 should be routed QueryReply reply = getReplyWithResults(g.bytes(), 10, addr1.getAddress(), token1); router.reply = null; handler.handleMessage(reply, null, replyHandler1); assertNotNull(router.reply); // Replies from addr2 should be routed reply = getReplyWithResults(g.bytes(), 10, addr2.getAddress(), token2); router.reply = null; handler.handleMessage(reply, null, replyHandler2); assertNotNull(router.reply); // Too many replies from addr2 should be ignored reply = getReplyWithResults(g.bytes(), 1, addr2.getAddress(), token2, 10); router.reply = null; handler.handleMessage(reply, null, replyHandler2); assertNull(router.reply); // New query g = new GUID(GUID.makeGuid()); replyHandler1.m = null; replyHandler2.m = null; // RNVM from addr1 should be acked rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler1); token1 = assertACKSent(replyHandler1, 10); // RNVM from addr2 should be ignored rnvm = factory.create(g, 10); router.numToRequest = 10; handler.handleMessage(rnvm, null, replyHandler2); assertNull(replyHandler2.m); // Replies from addr1 should be routed reply = getReplyWithResults(g.bytes(), 10, addr1.getAddress(), token1); router.reply = null; handler.handleMessage(reply, null, replyHandler1); assertNotNull(router.reply); } private static SecurityToken assertACKSent(MyReplyHandler rhandler, int numExpected) { assertNotNull(rhandler.m); assertTrue(rhandler.m instanceof LimeACKVendorMessage); LimeACKVendorMessage ack = (LimeACKVendorMessage) rhandler.m; assertEquals(numExpected, ack.getNumResults()); assertNotNull(ack.getSecurityToken()); return ack.getSecurityToken(); } private QueryReply getReplyWithResults(byte[] guid, int numResults, byte[] addr, SecurityToken token, boolean needsPush) { return getReplyWithResults(guid, numResults, addr, token, 0, needsPush); } private QueryReply getReplyWithResults(byte[] guid, int numResults, byte[] addr, SecurityToken token) { return getReplyWithResults(guid, numResults, addr, token, 0, false); } private QueryReply getReplyWithResults(byte[] guid, int numResults, byte[] addr, SecurityToken token, int offset) { return getReplyWithResults(guid, numResults, addr, token, offset, false); } private QueryReply getReplyWithResults(byte[] guid, int numResults, byte[] addr, SecurityToken token, int offset, boolean needsPush) { Response[] res = new Response[numResults]; byte[] randomBytes = new byte[20]; try { for(int i = 0; i < res.length; i++) { random.nextBytes(randomBytes); URN urn = URN.createSHA1UrnFromBytes(randomBytes); res[i] = responseFactory.createResponse(10, 10, "susheel" + i + offset, urn); } } catch(IOException misused) {} return queryReplyFactory.createQueryReply(guid, (byte) 1, 1, addr, 0, res, GUID.makeGuid(), new byte[0], needsPush, false, true, true, false, false, true, null, token); } private static class MyMessageRouter implements MessageRouter { volatile QueryReply reply; volatile int numToRequest; volatile long timeToExpire; volatile boolean isAlive = true; private ReplyNumberVendorMessage bypassedReply; private QueryReply bypassedQueryReply; public int getNumOOBToRequest(ReplyNumberVendorMessage reply) { return numToRequest; } public long getOOBExpireTime() { return timeToExpire; } public void handleQueryReply(QueryReply queryReply, ReplyHandler handler) { this.reply = queryReply; } public boolean isQueryAlive(GUID guid) { return isAlive; } public boolean addBypassedSource(ReplyNumberVendorMessage reply, ReplyHandler handler) { bypassedReply = reply; return true; } public boolean addBypassedSource(QueryReply reply, ReplyHandler handler) { bypassedQueryReply = reply; return true; } public void addMessageHandler(Class<? extends Message> clazz, MessageHandler handler) { } public void addMulticastMessageHandler(Class<? extends Message> clazz, MessageHandler handler) { } public void addUDPMessageHandler(Class<? extends Message> clazz, MessageHandler handler) { } public void broadcastPingRequest(PingRequest ping) { } public void downloadFinished(GUID guid) throws IllegalArgumentException { } public void forwardInspectionRequestToLeaves(InspectionRequest ir) { } public void forwardQueryRequestToLeaves(QueryRequest query, ReplyHandler handler) { } public MessageHandler getMessageHandler(Class<? extends Message> clazz) { return null; } public MessageHandler getMulticastMessageHandler( Class<? extends Message> clazz) { return null; } public String getPingRouteTableDump() { return null; } public String getPushRouteTableDump() { return null; } public Set<GUESSEndpoint> getQueryLocs(GUID guid) { return null; } public QueryRouteTable getQueryRouteTable() { return null; } public String getQueryRouteTableDump() { return null; } public MessageHandler getUDPMessageHandler( Class<? extends Message> clazz) { return null; } public void handleMessage(Message msg, ReplyHandler receivingConnection) { } public void handleMulticastMessage(Message msg, InetSocketAddress addr) { } public void handleUDPMessage(Message msg, InetSocketAddress addr) { } public void start() { } public boolean isHostUnicastQueried(GUID guid, IpPort host) { return false; } public boolean sendInitialQuery(QueryRequest query, RoutedConnection mc) { return false; } public void originateQueryGUID(byte[] guid) { } public void queryKilled(GUID guid) throws IllegalArgumentException { } public void registerMessageListener(byte[] guid, MessageListener ml) { } public void removeConnection(ReplyHandler rh) { } public Iterable<QueryReply> responsesToQueryReplies( Response[] responses, QueryRequest queryRequest) { return null; } public Iterable<QueryReply> responsesToQueryReplies( Response[] responses, QueryRequest queryRequest, int num, SecurityToken tok) { return null; } public void sendDynamicQuery(QueryRequest query) { } public void sendMulticastPushRequest(PushRequest push) { } public void sendPingRequest(PingRequest request, RoutedConnection connection) { } public void sendPushRequest(PushRequest push) throws IOException { } public void setMessageHandler(Class<? extends Message> clazz, MessageHandler handler) { } public void setMulticastMessageHandler(Class<? extends Message> clazz, MessageHandler handler) { } public void setUDPMessageHandler(Class<? extends Message> clazz, MessageHandler handler) { } public void unregisterMessageListener(byte[] guid, MessageListener ml) { } public ReplyHandler getPushHandler(byte[] guid) { return null; } public void setPersonalFilter(SpamFilter personalFilter) { } public boolean isPersonalSpam(Message m) { return false; } public void stop() { } public void initialize() { } public String getServiceName() { // TODO Auto-generated method stub return null; } } private static class MyReplyHandler extends ReplyHandlerStub { volatile Message m; final InetAddress addr; final int port; MyReplyHandler(InetAddress addr, int port) { this.addr = addr; this.port = port; } @Override public InetAddress getInetAddress() { return addr; } @Override public String getAddress() { return addr.getHostAddress(); } @Override public int getPort() { return port; } @Override public void reply(Message m) { this.m = m; } } }