package com.limegroup.gnutella; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; import java.io.InterruptedIOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.HashSet; import java.util.Map; import java.util.Set; import junit.framework.Test; import com.limegroup.gnutella.downloader.ManagedDownloader; import com.limegroup.gnutella.downloader.TestFile; import com.limegroup.gnutella.downloader.TestUploader; import com.limegroup.gnutella.guess.OnDemandUnicaster; import com.limegroup.gnutella.guess.QueryKey; import com.limegroup.gnutella.messages.Message; import com.limegroup.gnutella.messages.PingReply; import com.limegroup.gnutella.messages.PingRequest; import com.limegroup.gnutella.messages.QueryReply; import com.limegroup.gnutella.messages.QueryRequest; import com.limegroup.gnutella.messages.vendor.MessagesSupportedVendorMessage; import com.limegroup.gnutella.messages.vendor.ReplyNumberVendorMessage; import com.limegroup.gnutella.settings.ConnectionSettings; import com.limegroup.gnutella.settings.SearchSettings; import com.limegroup.gnutella.settings.SharingSettings; import com.limegroup.gnutella.settings.UploadSettings; import com.limegroup.gnutella.stubs.ActivityCallbackStub; import com.limegroup.gnutella.util.CommonUtils; import com.limegroup.gnutella.util.PrivilegedAccessor; /** * Checks whether (multi)leaves avoid forwarding messages to ultrapeers, do * redirects properly, etc. The test includes a leaf attached to 3 * Ultrapeers. */ public class ClientSideOOBRequeryTest extends ClientSideTestCase { private static final int UPLOADER_PORT = 10000; /** * Ultrapeer 1 UDP connection. */ private static DatagramSocket[] UDP_ACCESS; public ClientSideOOBRequeryTest(String name) { super(name); } public static Test suite() { return buildTestSuite(ClientSideOOBRequeryTest.class); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } private static void doSettings() { TIMEOUT = 4000; SharingSettings.EXTENSIONS_TO_SHARE.setValue("txt;mp3"); // get the resource file for com/limegroup/gnutella File mp3 = CommonUtils.getResourceFile("com/limegroup/gnutella/metadata/mpg1layIII_0h_58k-VBRq30_frame1211_44100hz_joint_XingTAG_sample.mp3"); // now move them to the share dir CommonUtils.copy(mp3, new File(_sharedDir, "metadata.mp3")); ConnectionSettings.DO_NOT_BOOTSTRAP.setValue(true); } ///////////////////////// Actual Tests //////////////////////////// // MUST RUN THIS TEST FIRST public void testNoDownloadQueryDonePurge() throws Exception { DatagramPacket pack = null; UDP_ACCESS = new DatagramSocket[10]; for (int i = 0; i < UDP_ACCESS.length; i++) UDP_ACCESS[i] = new DatagramSocket(); for (int i = 0; i < testUP.length; i++) { assertTrue("should be open", testUP[i].isOpen()); assertTrue("should be up -> leaf", testUP[i].isSupernodeClientConnection()); drain(testUP[i], 100); // OOB client side needs server side leaf guidance testUP[i].send(MessagesSupportedVendorMessage.instance()); testUP[i].flush(); } PrivilegedAccessor.setValue(RouterService.getUdpService(),"_acceptedSolicitedIncoming",Boolean.TRUE); PrivilegedAccessor.setValue(RouterService.getUdpService(),"_acceptedUnsolicitedIncoming",Boolean.TRUE); PrivilegedAccessor.setValue(RouterService.getAcceptor(),"_acceptedIncoming",Boolean.TRUE); // ---------------------------------------- Thread.sleep(250); // we should now be guess capable and tcp incoming capable.... assertTrue(RouterService.isGUESSCapable()); assertTrue(RouterService.acceptedIncomingConnection()); // set smaller clear times so we can test in a timely fashion keepAllAlive(testUP); // clear up any messages before we begin the test. drainAll(); Message m = null; byte[] guid = RouterService.newQueryGUID(); RouterService.query(guid, "whatever"); // i need to pretend that the UI is showing the user the query still ((MyCallback)getCallback()).setGUID(new GUID(guid)); QueryRequest qr = (QueryRequest) getFirstInstanceOfMessageType(testUP[0], QueryRequest.class); assertNotNull(qr); assertTrue(qr.desiresOutOfBandReplies()); // ok, the leaf is sending OOB queries - good stuff, now we should send // a lot of results back and make sure it buffers the bypassed OOB ones for (int i = 0; i < testUP.length; i++) { Response[] res = new Response[200]; for (int j = 0; j < res.length; j++) res[j] = new Response(10+j+i, 10+j+i, "whatever "+ j + i); m = new QueryReply(qr.getGUID(), (byte) 1, 6355, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // wait for processing Thread.sleep(2000); for (int i = 0; i < UDP_ACCESS.length; i++) { ReplyNumberVendorMessage vm = new ReplyNumberVendorMessage(new GUID(qr.getGUID()), i+1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); vm.write(baos); pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[i].send(pack); } // wait for processing Thread.sleep(1000); { // all the UDP ReplyNumberVMs should have been bypassed Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNotNull(endpoints); assertEquals(UDP_ACCESS.length, endpoints.size()); } { // now we should make sure MessageRouter clears the map RouterService.stopQuery(new GUID(qr.getGUID())); Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } ((MyCallback)getCallback()).clearGUID(); } public void testDownloadDoneQueryDonePurge() throws Exception { keepAllAlive(testUP); // clear up any messages before we begin the test. drainAll(); // luckily there is hacky little way to go through the download paces - // download from yourself :) . Message m = null; byte[] guid = RouterService.newQueryGUID(); RouterService.query(guid, "berkeley"); ((MyCallback)getCallback()).setGUID(new GUID(guid)); QueryRequest qr = (QueryRequest) getFirstInstanceOfMessageType(testUP[0], QueryRequest.class); assertNotNull(qr); assertTrue(qr.desiresOutOfBandReplies()); // just return ONE real result and the rest junk { // get a correct response object QueryRequest qrTemp = QueryRequest.createQuery("berkeley"); testUP[0].send(qrTemp); testUP[0].flush(); } Response resp = null; QueryReply reply = null; reply = (QueryReply) getFirstInstanceOfMessageType(testUP[0], QueryReply.class); assertNotNull(reply); resp = (Response) (reply.getResultsAsList()).get(0); assertNotNull(resp); Response[] res = new Response[] { resp }; // this isn't really needed but just for completeness send it back to // the test Leaf m = new QueryReply(guid, (byte) 1, SERVER_PORT, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[0].send(m); testUP[0].flush(); // send back a lot of results via TCP so you konw the UDP one will be // bypassed for (int i = 0; i < testUP.length; i++) { res = new Response[75]; for (int j = 0; j < res.length; j++) res[j] = new Response(10+j+i, 10+j+i, "berkeley "+ j + i); m = new QueryReply(guid, (byte) 1, testUP[0].getPort(), myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // allow for processing Thread.sleep(3000); { // now we should make sure MessageRouter has not bypassed anything // yet Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } // send back a UDP response and make sure it was saved in bypassed... { ReplyNumberVendorMessage vm = new ReplyNumberVendorMessage(new GUID(guid), 1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); vm.write(baos); DatagramPacket pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[0].send(pack); } // allow for processing Thread.sleep(500); { // all the UDP ReplyNumberVMs should have been bypassed Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(guid)); assertNotNull(endpoints); assertEquals(1, endpoints.size()); } // now do the download, wait for it to finish, and then bypassed results // should be empty again RemoteFileDesc rfd = resp.toRemoteFileDesc(reply.getHostData()); assertFalse("file should not be saved yet", new File( _savedDir, "berkeley.txt").exists()); assertTrue("file should be shared", new File(_sharedDir, "berkeley.txt").exists()); RouterService.download(new RemoteFileDesc[] { rfd }, false, new GUID(guid)); ((MyCallback)getCallback()).clearGUID(); // sleep to make sure the download starts Thread.sleep(10000); assertTrue("file should saved", new File( _savedDir, "berkeley.txt").exists()); assertTrue("file should be shared", new File(_sharedDir, "berkeley.txt").exists()); { // now we should make sure MessageRouter clears the map Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } } public void testQueryAliveNoPurge() throws Exception { keepAllAlive(testUP); // clear up any messages before we begin the test. drainAll(); // luckily there is hacky little way to go through the download paces - // download from yourself :) . Message m = null; byte[] guid = RouterService.newQueryGUID(); RouterService.query(guid, "berkeley"); ((MyCallback)getCallback()).setGUID(new GUID(guid)); QueryRequest qr = (QueryRequest) getFirstInstanceOfMessageType(testUP[0], QueryRequest.class); assertNotNull(qr); assertTrue(qr.desiresOutOfBandReplies()); // just return ONE real result and the rest junk Response resp = null; QueryReply reply = null; { // get a correct response object QueryRequest qrTemp = QueryRequest.createQuery("berkeley"); testUP[0].send(qrTemp); testUP[0].flush(); reply = (QueryReply) getFirstInstanceOfMessageType(testUP[0], QueryReply.class); assertNotNull(reply); resp = (Response) (reply.getResultsAsList()).get(0); } assertNotNull(reply); assertNotNull(resp); Response[] res = new Response[] { resp }; // this isn't really needed but just for completeness send it back to // the test Leaf m = new QueryReply(guid, (byte) 1, SERVER_PORT, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[0].send(m); testUP[0].flush(); // send back a lot of results via TCP so you konw the UDP one will be // bypassed for (int i = 0; i < testUP.length; i++) { res = new Response[75]; for (int j = 0; j < res.length; j++) res[j] = new Response(10+j+i, 10+j+i, "berkeley "+ j + i); m = new QueryReply(guid, (byte) 1, testUP[0].getPort(), myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // allow for processing Thread.sleep(3000); { // now we should make sure MessageRouter has not bypassed anything // yet Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } // send back a UDP response and make sure it was saved in bypassed... { ReplyNumberVendorMessage vm = new ReplyNumberVendorMessage(new GUID(guid), 1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); vm.write(baos); DatagramPacket pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[0].send(pack); } // allow for processing Thread.sleep(500); { // all the UDP ReplyNumberVMs should have been bypassed Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(guid)); assertNotNull(endpoints); assertEquals(1, endpoints.size()); } // now do the download, wait for it to finish, and then bypassed results // should not be empty since the query is still alive RemoteFileDesc rfd = resp.toRemoteFileDesc(reply.getHostData()); assertFalse("file should not be saved yet", new File( _savedDir, "berkeley.txt").exists()); assertTrue("file should be shared", new File(_sharedDir, "berkeley.txt").exists()); RouterService.download(new RemoteFileDesc[] { rfd }, false, new GUID(guid)); // sleep to make sure the download starts Thread.sleep(5000); assertTrue("file should saved", new File( _savedDir, "berkeley.txt").exists()); assertTrue("file should be shared", new File(_sharedDir, "berkeley.txt").exists()); { // all the UDP ReplyNumberVMs should have been bypassed Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(guid)); assertNotNull(endpoints); assertEquals(1, endpoints.size()); } RouterService.stopQuery(new GUID(guid)); { // now we should make sure MessageRouter clears the map Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } } public void testDownloadProgressQueryDoneNoPurge() throws Exception { keepAllAlive(testUP); // clear up any messages before we begin the test. drainAll(); // luckily there is hacky little way to go through the download paces - // download from yourself :) . Message m = null; byte[] guid = RouterService.newQueryGUID(); RouterService.query(guid, "metadata"); ((MyCallback)getCallback()).setGUID(new GUID(guid)); QueryRequest qr = (QueryRequest) getFirstInstanceOfMessageType(testUP[0], QueryRequest.class); assertNotNull(qr); assertTrue(qr.desiresOutOfBandReplies()); // just return ONE real result and the rest junk Response resp = null; QueryReply reply = null; { // get a correct response object QueryRequest qrTemp = QueryRequest.createQuery("metadata"); testUP[0].send(qrTemp); testUP[0].flush(); reply = (QueryReply) getFirstInstanceOfMessageType(testUP[0], QueryReply.class); assertNotNull(reply); resp = (Response) (reply.getResultsAsList()).get(0); } assertNotNull(reply); assertNotNull(resp); Response[] res = new Response[] { resp }; // this isn't really needed but just for completeness send it back to // the test Leaf m = new QueryReply(guid, (byte) 1, SERVER_PORT, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[0].send(m); testUP[0].flush(); // send back a lot of results via TCP so you konw the UDP one will be // bypassed for (int i = 0; i < testUP.length; i++) { res = new Response[75]; for (int j = 0; j < res.length; j++) res[j] = new Response(10+j+i, 10+j+i, "metadata "+ j + i); m = new QueryReply(guid, (byte) 1, testUP[0].getPort(), myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // allow for processing Thread.sleep(3000); { // now we should make sure MessageRouter has not bypassed anything // yet Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } // send back a UDP response and make sure it was saved in bypassed... { ReplyNumberVendorMessage vm = new ReplyNumberVendorMessage(new GUID(guid), 1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); vm.write(baos); DatagramPacket pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[0].send(pack); } // allow for processing Thread.sleep(500); { // all the UDP ReplyNumberVMs should have been bypassed Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(guid)); assertNotNull(endpoints); assertEquals(1, endpoints.size()); } // now do the download, wait for it to finish, and then bypassed results // should be empty again RemoteFileDesc rfd = resp.toRemoteFileDesc(reply.getHostData()); assertFalse("file should not be saved yet", new File( _savedDir, "metadata.mp3").exists()); assertTrue("file should be shared", new File(_sharedDir, "metadata.mp3").exists()); RouterService.download(new RemoteFileDesc[] { rfd }, false, new GUID(guid)); UploadSettings.UPLOAD_SPEED.setValue(5); RouterService.stopQuery(new GUID(guid)); ((MyCallback)getCallback()).clearGUID(); { // download still in progress, don't purge Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(guid)); assertNotNull(endpoints); assertEquals(1, endpoints.size()); } UploadSettings.UPLOAD_SPEED.setValue(100); // sleep to make sure the download starts Thread.sleep(10000); assertTrue("file should saved", new File( _savedDir, "metadata.mp3").exists()); assertTrue("file should be shared", new File(_sharedDir, "metadata.mp3").exists()); { // now we should make sure MessageRouter clears the map Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } } public void testBusyDownloadLocatesSources() throws Exception { keepAllAlive(testUP); // clear up any messages before we begin the test. drainAll(); DatagramPacket pack = null; Message m = null; byte[] guid = RouterService.newQueryGUID(); RouterService.query(guid, "whatever"); // i need to pretend that the UI is showing the user the query still ((MyCallback)getCallback()).setGUID(new GUID(guid)); QueryRequest qr = (QueryRequest) getFirstInstanceOfMessageType(testUP[0], QueryRequest.class); assertNotNull(qr); assertTrue(qr.desiresOutOfBandReplies()); // ok, the leaf is sending OOB queries - good stuff, now we should send // a lot of results back and make sure it buffers the bypassed OOB ones for (int i = 0; i < testUP.length; i++) { Response[] res = new Response[200]; for (int j = 0; j < res.length; j++) res[j] = new Response(10+j+i, 10+j+i, "whatever "+ j + i); m = new QueryReply(qr.getGUID(), (byte) 1, 6355, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // create a test uploader and send back that response TestUploader uploader = new TestUploader("whatever", UPLOADER_PORT); uploader.setBusy(true); RemoteFileDesc rfd = makeRFD("GLIQY64M7FSXBSQEZY37FIM5QQSA2OUJ"); // wait for processing Thread.sleep(1500); for (int i = 0; i < UDP_ACCESS.length; i++) { ReplyNumberVendorMessage vm = new ReplyNumberVendorMessage(new GUID(qr.getGUID()), i+1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); vm.write(baos); pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[i].send(pack); } // wait for processing Thread.sleep(500); { // all the UDP ReplyNumberVMs should have been bypassed Map _bypassedResults = (Map)PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNotNull(endpoints); assertEquals(UDP_ACCESS.length, endpoints.size()); } long currTime = System.currentTimeMillis(); Downloader downloader = RouterService.download(new RemoteFileDesc[] { rfd }, false, new GUID(guid)); final int MAX_TRIES = 60; for (int i = 0; i <= MAX_TRIES; i++) { Thread.sleep(1000); if (downloader.getState() == Downloader.ITERATIVE_GUESSING) break; if (i == MAX_TRIES) fail("didn't GUESS!!"); } // we should start getting guess queries on all UDP ports, actually // querykey requests for (int i = 0; i < UDP_ACCESS.length; i++) { boolean gotPing = false; while (!gotPing) { try { byte[] datagramBytes = new byte[1000]; pack = new DatagramPacket(datagramBytes, 1000); UDP_ACCESS[i].setSoTimeout(10000); // may need to wait UDP_ACCESS[i].receive(pack); InputStream in = new ByteArrayInputStream(pack.getData()); m = Message.read(in); m.hop(); if (m instanceof PingRequest) gotPing = ((PingRequest) m).isQueryKeyRequest(); } catch (InterruptedIOException iioe) { fail("was successful for " + i, iioe); } } } //Thread.sleep((UDP_ACCESS.length * 1000) - //(System.currentTimeMillis() - currTime)); int guessWaitTime = ((Integer)PrivilegedAccessor.getValue(ManagedDownloader.class,"GUESS_WAIT_TIME")).intValue(); Thread.sleep(guessWaitTime+2000); assertEquals(Downloader.BUSY, downloader.getState()); ((MyCallback)getCallback()).clearGUID(); downloader.stop(); Thread.sleep(1000); { // now we should make sure MessageRouter clears the map Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } uploader.stopThread(); } public void testDownloadFinishes() throws Exception { keepAllAlive(testUP); // clear up any messages before we begin the test. drainAll(); DatagramPacket pack = null; Message m = null; byte[] guid = RouterService.newQueryGUID(); RouterService.query(guid, "whatever"); // i need to pretend that the UI is showing the user the query still ((MyCallback)getCallback()).setGUID(new GUID(guid)); QueryRequest qr = (QueryRequest) getFirstInstanceOfMessageType(testUP[0], QueryRequest.class); assertNotNull(qr); assertTrue(qr.desiresOutOfBandReplies()); // ok, the leaf is sending OOB queries - good stuff, now we should send // a lot of results back and make sure it buffers the bypassed OOB ones for (int i = 0; i < testUP.length; i++) { Response[] res = new Response[200]; for (int j = 0; j < res.length; j++) res[j] = new Response(10+j+i, 10+j+i, "whatever "+ j + i); m = new QueryReply(qr.getGUID(), (byte) 1, 6355, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // create a test uploader and send back that response TestUploader uploader = new TestUploader("whatever", UPLOADER_PORT); uploader.setBusy(true); URN urn = TestFile.hash(); RemoteFileDesc rfd = makeRFD(urn); // wait for processing Thread.sleep(1500); // just do it for 1 UDP guy { ReplyNumberVendorMessage vm = new ReplyNumberVendorMessage(new GUID(qr.getGUID()), 1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); vm.write(baos); pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[0].send(pack); } // wait for processing Thread.sleep(500); { // all the UDP ReplyNumberVMs should have been bypassed Map _bypassedResults = (Map)PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNotNull(endpoints); assertEquals(1, endpoints.size()); } long currTime = System.currentTimeMillis(); Downloader downloader = RouterService.download(new RemoteFileDesc[] { rfd }, false, new GUID(guid)); final int MAX_TRIES = 60; for (int i = 0; i <= MAX_TRIES; i++) { Thread.sleep(500); if (downloader.getState() == Downloader.ITERATIVE_GUESSING) break; if (i == MAX_TRIES) fail("didn't GUESS!!"); } // we should get a query key request { boolean gotPing = false; while (!gotPing) { byte[] datagramBytes = new byte[1000]; pack = new DatagramPacket(datagramBytes, 1000); UDP_ACCESS[0].setSoTimeout(10000); // may need to wait UDP_ACCESS[0].receive(pack); InputStream in = new ByteArrayInputStream(pack.getData()); m = Message.read(in); m.hop(); if (m instanceof PingRequest) gotPing = ((PingRequest) m).isQueryKeyRequest(); } } // send back a query key QueryKey qk = QueryKey.getQueryKey(InetAddress.getLocalHost(), SERVER_PORT); { byte[] ip = new byte[] {(byte)127, (byte) 0, (byte) 0, (byte) 1}; PingReply pr = PingReply.createQueryKeyReply(GUID.makeGuid(), (byte) 1, UDP_ACCESS[0].getLocalPort(), ip, 10, 10, false, qk); ByteArrayOutputStream baos = new ByteArrayOutputStream(); pr.write(baos); pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[0].send(pack); } Thread.sleep(500); // ensure that it gets into the OnDemandUnicaster { // now we should make sure MessageRouter retains the key Map _queryKeys = (Map) PrivilegedAccessor.getValue(OnDemandUnicaster.class, "_queryKeys"); assertNotNull(_queryKeys); assertEquals(1, _queryKeys.size()); } { // confirm a URN query boolean gotQuery = false; while (!gotQuery) { byte[] datagramBytes = new byte[1000]; pack = new DatagramPacket(datagramBytes, 1000); UDP_ACCESS[0].setSoTimeout(10000); // may need to wait UDP_ACCESS[0].receive(pack); InputStream in = new ByteArrayInputStream(pack.getData()); m = Message.read(in); if (m instanceof QueryRequest) { QueryRequest qReq = (QueryRequest) m; Set queryURNs = qReq.getQueryUrns(); gotQuery = queryURNs.contains(urn); if (gotQuery) gotQuery = qk.equals(qReq.getQueryKey()); } } } long timeoutVal = 8000 - (System.currentTimeMillis() - currTime); Thread.sleep(timeoutVal > 0 ? timeoutVal : 0); assertEquals(Downloader.BUSY, downloader.getState()); // purge front end of query ((MyCallback)getCallback()).clearGUID(); // create a new Uploader to service the download TestUploader uploader2 = new TestUploader("whatever", UPLOADER_PORT+1); uploader2.setRate(100); { // send back a query request, the TestUploader should service upload rfd = makeRFD(urn, UPLOADER_PORT + 1); Response[] res = new Response[] { new Response(10, 10, "whatever") }; m = new QueryReply(qr.getGUID(), (byte) 1, UPLOADER_PORT+1, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); m.write(baos); pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[0].send(pack); } // after a while, the download should finish, the bypassed results // should be discarded Thread.sleep(10000); assertEquals(Downloader.COMPLETE, downloader.getState()); { // now we should make sure MessageRouter clears the map Map _bypassedResults = (Map)PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } uploader.stopThread(); } public void testUsesCachedQueryKeys() throws Exception { keepAllAlive(testUP); // clear up any messages before we begin the test. drainAll(); DatagramPacket pack = null; Message m = null; byte[] guid = RouterService.newQueryGUID(); RouterService.query(guid, "whatever"); // i need to pretend that the UI is showing the user the query still ((MyCallback)getCallback()).setGUID(new GUID(guid)); QueryRequest qr = (QueryRequest) getFirstInstanceOfMessageType(testUP[0], QueryRequest.class); assertNotNull(qr); assertTrue(qr.desiresOutOfBandReplies()); // ok, the leaf is sending OOB queries - good stuff, now we should send // a lot of results back and make sure it buffers the bypassed OOB ones for (int i = 0; i < testUP.length; i++) { Response[] res = new Response[200]; for (int j = 0; j < res.length; j++) res[j] = new Response(10+j+i, 10+j+i, "whatever "+ j + i); m = new QueryReply(qr.getGUID(), (byte) 1, 6355, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // create a test uploader and send back that response TestUploader uploader = new TestUploader("whatever", UPLOADER_PORT); uploader.setBusy(true); URN urn = URN.createSHA1Urn("urn:sha1:GLIQY64M7FSXBSQEZY37FIM5QQSA2OUJ"); RemoteFileDesc rfd = makeRFD(urn); // wait for processing Thread.sleep(1500); // send back ReplyNumberVMs that should be bypassed for (int i = 0; i < UDP_ACCESS.length; i++) { ReplyNumberVendorMessage vm = new ReplyNumberVendorMessage(new GUID(qr.getGUID()), i+1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); vm.write(baos); pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[i].send(pack); } // wait for processing Thread.sleep(500); { // all the UDP ReplyNumberVMs should have been bypassed Map _bypassedResults = (Map)PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNotNull(endpoints); assertEquals(UDP_ACCESS.length, endpoints.size()); } // Prepopulate Query Keys QueryKey qk = QueryKey.getQueryKey(InetAddress.getLocalHost(), SERVER_PORT); for (int i = 0; i < UDP_ACCESS.length; i++) { byte[] ip = new byte[] {(byte)127, (byte) 0, (byte) 0, (byte) 1}; PingReply pr = PingReply.createQueryKeyReply(GUID.makeGuid(), (byte) 1, UDP_ACCESS[i].getLocalPort(), ip, 10, 10, false, qk); pr.hop(); OnDemandUnicaster.handleQueryKeyPong(pr); } // confirm download will try to GUESS long currTime = System.currentTimeMillis(); Downloader downloader = RouterService.download(new RemoteFileDesc[] { rfd }, false, new GUID(guid)); final int MAX_TRIES = 60; for (int i = 0; i <= MAX_TRIES; i++) { Thread.sleep(500); if (downloader.getState() == Downloader.ITERATIVE_GUESSING) break; if (i == MAX_TRIES) fail("didn't GUESS!!"); } // we should start getting guess queries on all UDP ports for (int i = 0; i < UDP_ACCESS.length; i++) { boolean gotQuery = false; while (!gotQuery) { try { byte[] datagramBytes = new byte[1000]; pack = new DatagramPacket(datagramBytes, 1000); UDP_ACCESS[i].setSoTimeout(10000); // may need to wait UDP_ACCESS[i].receive(pack); InputStream in = new ByteArrayInputStream(pack.getData()); m = Message.read(in); if (m instanceof QueryRequest) { QueryRequest qReq = (QueryRequest) m; Set queryURNs = qReq.getQueryUrns(); gotQuery = queryURNs.contains(urn); if (gotQuery) gotQuery = qk.equals(qReq.getQueryKey()); } } catch (InterruptedIOException iioe) { assertTrue("was successful for " + i, false); } } } Thread.sleep((UDP_ACCESS.length * 1500) - (System.currentTimeMillis() - currTime)); assertEquals(Downloader.BUSY, downloader.getState()); ((MyCallback)getCallback()).clearGUID(); downloader.stop(); Thread.sleep(1000); { // now we should make sure MessageRouter clears the map Map _bypassedResults = (Map)PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } uploader.stopThread(); } public void testMultipleDownloadsNoPurge() throws Exception { keepAllAlive(testUP); // clear up any messages before we begin the test. drainAll(); DatagramPacket pack = null; Message m = null; byte[] guid = RouterService.newQueryGUID(); RouterService.query(guid, "whatever"); // i need to pretend that the UI is showing the user the query still ((MyCallback)getCallback()).setGUID(new GUID(guid)); QueryRequest qr = (QueryRequest) getFirstInstanceOfMessageType(testUP[0], QueryRequest.class); assertNotNull(qr); assertTrue(qr.desiresOutOfBandReplies()); // ok, the leaf is sending OOB queries - good stuff, now we should send // a lot of results back and make sure it buffers the bypassed OOB ones for (int i = 0; i < testUP.length; i++) { Response[] res = new Response[200]; for (int j = 0; j < res.length; j++) res[j] = new Response(10+j+i, 10+j+i, "whatever "+ j + i); m = new QueryReply(qr.getGUID(), (byte) 1, 6355, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // create a test uploader and send back that response TestUploader uploader = new TestUploader("whatever", UPLOADER_PORT); uploader.setBusy(true); RemoteFileDesc rfd = makeRFD("GLIQY64M7FSXBSQEZY37FIM5QQSA2OUJ"); TestUploader uploader2 = new TestUploader("whatever", UPLOADER_PORT*2); uploader2.setBusy(true); RemoteFileDesc rfd2 = makeRFD("GLIQY64M7FSXBSQEZY37FIM5QQSASUSH"); // wait for processing Thread.sleep(1500); { // bypass 1 result only ReplyNumberVendorMessage vm = new ReplyNumberVendorMessage(new GUID(qr.getGUID()), 1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); vm.write(baos); pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[0].send(pack); } // wait for processing Thread.sleep(500); { // all the UDP ReplyNumberVMs should have been bypassed Map _bypassedResults = (Map)PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNotNull(endpoints); assertEquals(1, endpoints.size()); } Downloader downloader = RouterService.download(new RemoteFileDesc[] { rfd }, false, new GUID(guid)); // Don't try using the same default file Downloader downloader2 = RouterService.download(new RemoteFileDesc[] { rfd2 }, new GUID(guid), false, null, "anotherFile" ); // let downloaders do stuff final int MAX_TRIES = 60; boolean oneGood = false, twoGood = false; for (int i = 0; i <= MAX_TRIES; i++) { Thread.sleep(500); if (downloader.getState() == Downloader.BUSY) oneGood = true; if (downloader2.getState() == Downloader.BUSY) twoGood = true; if (oneGood && twoGood) break; if (i == MAX_TRIES) fail("didn't GUESS!!"); } ((MyCallback)getCallback()).clearGUID(); // isQueryAlive == false downloader.stop(); Thread.sleep(500); { // we should still have bypassed results since downloader2 alive Map _bypassedResults = (Map)PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNotNull(endpoints); assertEquals(1, endpoints.size()); } downloader2.stop(); Thread.sleep(1000); { // now we should make sure MessageRouter clears the map Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } uploader.stopThread(); uploader2.stopThread(); } // RUN THIS TEST LAST!! public void testUnicasterClearingCode() throws Exception { keepAllAlive(testUP); // clear up any messages before we begin the test. drainAll(); { // clear all the unicaster data structures Long[] longs = new Long[] { new Long(0), new Long(1) }; Class[] classTypes = new Class[] { Long.TYPE, Long.TYPE }; // now confirm that clearing code works Object ret = PrivilegedAccessor.invokeMethod(OnDemandUnicaster.class, "clearDataStructures", longs, classTypes); assertTrue(ret instanceof Boolean); assertTrue(((Boolean)ret).booleanValue()); } DatagramPacket pack = null; Message m = null; byte[] guid = RouterService.newQueryGUID(); RouterService.query(guid, "whatever"); // i need to pretend that the UI is showing the user the query still ((MyCallback)getCallback()).setGUID(new GUID(guid)); QueryRequest qr = (QueryRequest) getFirstInstanceOfMessageType(testUP[0], QueryRequest.class); assertNotNull(qr); assertTrue(qr.desiresOutOfBandReplies()); // ok, the leaf is sending OOB queries - good stuff, now we should send // a lot of results back and make sure it buffers the bypassed OOB ones for (int i = 0; i < testUP.length; i++) { Response[] res = new Response[200]; for (int j = 0; j < res.length; j++) res[j] = new Response(10+j+i, 10+j+i, "whatever "+ j + i); m = new QueryReply(qr.getGUID(), (byte) 1, 6355, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // create a test uploader and send back that response TestUploader uploader = new TestUploader("whatever", UPLOADER_PORT); uploader.setBusy(true); RemoteFileDesc rfd = makeRFD("GLIQY64M7FSXBSQEZY37FIM5QQSA2OUJ"); // wait for processing Thread.sleep(1500); for (int i = 0; i < UDP_ACCESS.length; i++) { ReplyNumberVendorMessage vm = new ReplyNumberVendorMessage(new GUID(qr.getGUID()), i+1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); vm.write(baos); pack = new DatagramPacket(baos.toByteArray(), baos.toByteArray().length, testUP[0].getInetAddress(), SERVER_PORT); UDP_ACCESS[i].send(pack); } // wait for processing Thread.sleep(500); { // all the UDP ReplyNumberVMs should have been bypassed Map _bypassedResults = (Map)PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(1, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNotNull(endpoints); assertEquals(UDP_ACCESS.length, endpoints.size()); } Downloader downloader = RouterService.download(new RemoteFileDesc[] { rfd }, false, new GUID(guid)); final int MAX_TRIES = 60; for (int i = 0; i <= MAX_TRIES; i++) { Thread.sleep(500); if (downloader.getState() == Downloader.ITERATIVE_GUESSING) break; if (i == MAX_TRIES) fail("didn't GUESS!!"); } // we should start getting guess queries on all UDP ports, actually // querykey requests for (int i = 0; i < UDP_ACCESS.length; i++) { boolean gotPing = false; while (!gotPing) { try { byte[] datagramBytes = new byte[1000]; pack = new DatagramPacket(datagramBytes, 1000); UDP_ACCESS[i].setSoTimeout(10000); // may need to wait UDP_ACCESS[i].receive(pack); InputStream in = new ByteArrayInputStream(pack.getData()); m = Message.read(in); m.hop(); if (m instanceof PingRequest) gotPing = ((PingRequest) m).isQueryKeyRequest(); } catch (InterruptedIOException iioe) { assertTrue("was successful for " + i, false); } } } // Prepopulate Query Keys QueryKey qk = QueryKey.getQueryKey(InetAddress.getLocalHost(), SERVER_PORT); for (int i = 0; i < (UDP_ACCESS.length/2); i++) { byte[] ip = new byte[] {(byte)127, (byte) 0, (byte) 0, (byte) 1}; PingReply pr = PingReply.createQueryKeyReply(GUID.makeGuid(), (byte) 1, UDP_ACCESS[i].getLocalPort(), ip, 10, 10, false, qk); pr.hop(); OnDemandUnicaster.handleQueryKeyPong(pr); } // ensure that it gets into the OnDemandUnicaster { // now we should make sure MessageRouter retains the key Map _queryKeys = (Map) PrivilegedAccessor.getValue(OnDemandUnicaster.class, "_queryKeys"); assertNotNull(_queryKeys); assertEquals((UDP_ACCESS.length/2), _queryKeys.size()); // now make sure some URNs are still buffered Map _bufferedURNs = (Map) PrivilegedAccessor.getValue(OnDemandUnicaster.class, "_bufferedURNs"); assertNotNull(_bufferedURNs); assertEquals((UDP_ACCESS.length/2), _bufferedURNs.size()); } // now until those guys get expired Thread.sleep(60 * 1000); { Long[] longs = new Long[] { new Long(0), new Long(1) }; Class[] classTypes = new Class[] { Long.TYPE, Long.TYPE }; // now confirm that clearing code works Object ret = PrivilegedAccessor.invokeMethod(OnDemandUnicaster.class, "clearDataStructures", longs, classTypes); assertTrue(ret instanceof Boolean); assertTrue(((Boolean)ret).booleanValue()); } // ensure that clearing worked { // now we should make sure MessageRouter retains the key Map _queryKeys = (Map) PrivilegedAccessor.getValue(OnDemandUnicaster.class, "_queryKeys"); assertNotNull(_queryKeys); assertEquals(0, _queryKeys.size()); // now make sure some URNs are still buffered Map _bufferedURNs = (Map) PrivilegedAccessor.getValue(OnDemandUnicaster.class, "_bufferedURNs"); assertNotNull(_bufferedURNs); assertEquals(0, _bufferedURNs.size()); } assertEquals(Downloader.BUSY, downloader.getState()); ((MyCallback)getCallback()).clearGUID(); downloader.stop(); Thread.sleep(1000); { // now we should make sure MessageRouter clears the map Map _bypassedResults = (Map) PrivilegedAccessor.getValue(RouterService.getMessageRouter(), "_bypassedResults"); assertNotNull(_bypassedResults); assertEquals(0, _bypassedResults.size()); Set endpoints = (Set) _bypassedResults.get(new GUID(qr.getGUID())); assertNull(endpoints); } } ////////////////////////////////////////////////////////////////// private RemoteFileDesc makeRFD(URN urn, int port) throws Exception { Set urns = new HashSet(); urns.add(urn); return new RemoteFileDesc("127.0.0.1", port, 1, "whatever", 10, GUID.makeGuid(), 1, false, 3, false, null, urns, false, false, "LIME", 0, new HashSet(), -1); } private RemoteFileDesc makeRFD(String sha1) throws Exception { URN urn = URN.createSHA1Urn("urn:sha1:" + sha1); return makeRFD(urn); } private RemoteFileDesc makeRFD(URN urn) throws Exception { return makeRFD(urn, UPLOADER_PORT); } public static Integer numUPs() { return new Integer(3); } private static byte[] myIP() { return new byte[] { (byte)127, (byte)0, 0, 1 }; } public static ActivityCallback getActivityCallback() { return new MyCallback(); } public static class MyCallback extends ActivityCallbackStub { public GUID aliveGUID = null; public void setGUID(GUID guid) { aliveGUID = guid; } public void clearGUID() { aliveGUID = null; } public boolean isQueryAlive(GUID guid) { if (aliveGUID != null) return (aliveGUID.equals(guid)); return false; } } }