package com.limegroup.gnutella.messages.vendor; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.Random; import java.util.Set; import java.util.TreeSet; import junit.framework.Test; import org.jmock.Expectations; import org.jmock.Mockery; import org.limewire.collection.BitNumbers; import org.limewire.collection.Range; import org.limewire.core.settings.UploadSettings; import org.limewire.gnutella.tests.LimeTestCase; import org.limewire.gnutella.tests.LimeTestUtils; import org.limewire.gnutella.tests.NetworkManagerStub; import org.limewire.io.BadGGEPBlockException; import org.limewire.io.BadGGEPPropertyException; import org.limewire.io.Connectable; import org.limewire.io.GGEP; import org.limewire.io.GUID; import org.limewire.io.IpPort; import org.limewire.io.IpPortImpl; import org.limewire.io.IpPortSet; import org.limewire.io.NetworkUtils; import org.limewire.util.ByteUtils; import org.limewire.util.StringUtils; import com.google.inject.AbstractModule; import com.google.inject.Inject; import com.google.inject.Injector; import com.limegroup.gnutella.DownloadManager; import com.limegroup.gnutella.NetworkManager; import com.limegroup.gnutella.PushEndpoint; import com.limegroup.gnutella.PushEndpointFactory; import com.limegroup.gnutella.UploadManager; import com.limegroup.gnutella.altlocs.AltLocManager; import com.limegroup.gnutella.altlocs.AlternateLocation; import com.limegroup.gnutella.altlocs.AlternateLocationFactory; import com.limegroup.gnutella.altlocs.PushAltLoc; import com.limegroup.gnutella.helpers.UrnHelper; import com.limegroup.gnutella.library.FileCollection; import com.limegroup.gnutella.library.FileDescStub; import com.limegroup.gnutella.library.GnutellaFileCollectionStub; import com.limegroup.gnutella.library.GnutellaFiles; import com.limegroup.gnutella.library.IncompleteFileCollection; import com.limegroup.gnutella.library.IncompleteFileDescStub; import com.limegroup.gnutella.library.LibraryStubModule; import com.limegroup.gnutella.messages.BadPacketException; import com.limegroup.gnutella.messages.Message.Network; import com.limegroup.gnutella.stubs.UploadManagerStub; public class HeadPongTest extends LimeTestCase { @Inject private HeadPongFactory headPongFactory; @Inject private Injector injector; private Mockery mockery; private DownloadManager downloadManager; private NetworkManagerStub networkManager; @Inject @GnutellaFiles private FileCollection gnutellaFileCollection; @Inject private IncompleteFileCollection incompleteFileCollection; public HeadPongTest(String name) { super(name); } public static Test suite() { return buildTestSuite(HeadPongTest.class); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } @Override public void setUp() throws Exception { mockery = new Mockery(); downloadManager = mockery.mock(DownloadManager.class); injector = LimeTestUtils.createInjectorNonEagerly(new AbstractModule() { @Override protected void configure() { bind(UploadManager.class).to(UploadManagerStub.class); bind(NetworkManager.class).to(NetworkManagerStub.class); bind(DownloadManager.class).toInstance(downloadManager); } }, new LibraryStubModule(), LimeTestUtils.createModule(this)); networkManager = (NetworkManagerStub) injector.getInstance(NetworkManager.class); networkManager.setAcceptedIncomingConnection(true); networkManager.setIncomingTLSEnabled(false); } @Override public void tearDown() throws Exception { mockery.assertIsSatisfied(); // TODO ? //SSLSettings.TLS_INCOMING.revertToDefault(); //altLocManager.purge(); } public void testReadBinary() throws Exception { PushEndpointFactory pushEndpointFactory = injector.getInstance(PushEndpointFactory.class); ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(0x1 | 0x2 | 0x4 | 0x8); // features (intervals, alt locs, push alt locs, fwt alt locs) out.write(0x2 | 0x8); // codes (partial file, downloading) out.write(new byte[] { 'S', 'A', 'M', 'B' }); // vendor out.write(-1); // queue status ByteUtils.short2beb((short)24, out); // length of forthcoming ranges. ByteUtils.int2beb(1, out); // ranges.... ByteUtils.int2beb(1000, out); ByteUtils.int2beb(1050, out); ByteUtils.int2beb(2001, out); ByteUtils.int2beb(2500, out); ByteUtils.int2beb(2525, out); //...ranges (1-1000, 1050-2001, 2500-2525) Random random = new Random(); byte[] g1 = new byte[16]; random.nextBytes(g1); PushEndpoint p1 = pushEndpointFactory.createPushEndpoint(g1, new IpPortSet(new IpPortImpl("1.2.3.4:5")), PushEndpoint.PLAIN, 0); byte[] p1b = p1.toBytes(false); byte[] g2 = new byte[16]; random.nextBytes(g2); PushEndpoint p2 = pushEndpointFactory.createPushEndpoint(g2, new IpPortSet(new IpPortImpl("2.3.4.5:6"), new IpPortImpl("3.4.5.6:7")), PushEndpoint.PLAIN, 0); byte[] p2b = p2.toBytes(false); ByteUtils.short2beb((short)(p1b.length + p2b.length), out); // length of forthcoming push locations. out.write(p1b); // push locations... out.write(p2b); // ...push locations ByteUtils.short2beb((short)18, out); // length of forthcoming alternate locations. out.write(new byte[] { 4, 5, 6, 7, 8, 0, 5, 6, 7, 8, 9, 0, 6, 7, 8, 9, 10, 0 } ); // alternate locations HeadPong pong = headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 1, out.toByteArray(), Network.UNKNOWN); assertTrue(pong.hasFile()); assertFalse(pong.hasCompleteFile()); Iterator<Range> iterator = pong.getRanges().iterator(); assertEquals(Range.createRange(1, 1000), iterator.next()); assertEquals(Range.createRange(1050, 2001), iterator.next()); assertEquals(Range.createRange(2500, 2525), iterator.next()); assertFalse(iterator.hasNext()); Set<IpPort> expectedLocs = new IpPortSet(new IpPortImpl("4.5.6.7:8"), new IpPortImpl("5.6.7.8:9"), new IpPortImpl("6.7.8.9:10")); assertEquals(expectedLocs, pong.getAltLocs()); Set<PushEndpoint> pushLocs = pong.getPushLocs(); assertEquals(2, pushLocs.size()); Iterator<PushEndpoint> peIterator = pushLocs.iterator(); PushEndpoint read1 = peIterator.next(); PushEndpoint read2 = peIterator.next(); assertFalse(peIterator.hasNext()); PushEndpoint m1, m2; // figure out which order the set put the PEs in... if(Arrays.equals(read1.getClientGUID(), g1)) { m1 = read1; m2 = read2; } else { m1 = read2; m2 = read1; } assertEquals(g1, m1.getClientGUID()); assertEquals(g2, m2.getClientGUID()); assertEquals(1, m1.getProxies().size()); assertEquals(2, m2.getProxies().size()); assertFalse(pong.isTLSCapable()); assertEquals("SAMB", pong.getVendor()); assertFalse(pong.isFirewalled()); assertEquals(-1, pong.getQueueStatus()); assertFalse(pong.isBusy()); assertTrue(pong.isDownloading()); assertFalse(pong.isRoutingBroken()); // Just a quick test, since we already have the outputstream built up, to make // sure binary won't work if version != 1 try { headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, out.toByteArray(), Network.UNKNOWN); fail("expected bpe!"); } catch(BadPacketException bpe) { assertInstanceof(BadGGEPBlockException.class, bpe.getCause()); } } public void testReadGGEP() throws Exception { PushEndpointFactory pushEndpointFactory = injector.getInstance(PushEndpointFactory.class); GGEP ggep = new GGEP(); ggep.put("F", (byte)0x1); // TLS capable. ggep.put("C", (byte)0x2 | 0x8); // response code (partial, downloading) ggep.put("V", new byte[] { 'S', 'A', 'M', 'B' } ); // vendor ggep.put("Q", (byte)-1); // queue status. byte[] ranges = new byte[24]; ByteUtils.int2beb(1, ranges, 0); ByteUtils.int2beb(1000, ranges, 4); ByteUtils.int2beb(1050, ranges, 8); ByteUtils.int2beb(2001, ranges, 12); ByteUtils.int2beb(2500, ranges, 16); ByteUtils.int2beb(2525, ranges, 20); ggep.put("R", ranges); // ranges Random random = new Random(); byte[] g1 = new byte[16]; random.nextBytes(g1); PushEndpoint p1 = pushEndpointFactory.createPushEndpoint(g1, new IpPortSet(new IpPortImpl("1.2.3.4:5")), PushEndpoint.PLAIN, 0); byte[] p1b = p1.toBytes(false); byte[] g2 = new byte[16]; random.nextBytes(g2); PushEndpoint p2 = pushEndpointFactory.createPushEndpoint(g2, new IpPortSet(new IpPortImpl("2.3.4.5:6"), new IpPortImpl("3.4.5.6:7")), PushEndpoint.PLAIN, 0); byte[] p2b = p2.toBytes(false); byte[] pushbytes = new byte[p1b.length + p2b.length]; System.arraycopy(p1b, 0, pushbytes, 0, p1b.length); System.arraycopy(p2b, 0, pushbytes, p1b.length, p2b.length); ggep.put("P", pushbytes); // push locations. ggep.put("A", new byte[] { 4, 5, 6, 7, 8, 0, 5, 6, 7, 8, 9, 0, 6, 7, 8, 9, 10, 0 } ); // alternate locations ggep.put("T", new byte[] { 0x60 } ); // TLS indexes into alternate locations ByteArrayOutputStream out = new ByteArrayOutputStream(); ggep.write(out); HeadPong pong = headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, out.toByteArray(), Network.UNKNOWN); assertTrue(pong.hasFile()); assertFalse(pong.hasCompleteFile()); Iterator<Range> iterator = pong.getRanges().iterator(); assertEquals(Range.createRange(1, 1000), iterator.next()); assertEquals(Range.createRange(1050, 2001), iterator.next()); assertEquals(Range.createRange(2500, 2525), iterator.next()); assertFalse(iterator.hasNext()); Set<IpPort> expectedLocs = new IpPortSet(new IpPortImpl("4.5.6.7:8"), new IpPortImpl("5.6.7.8:9"), new IpPortImpl("6.7.8.9:10")); assertEquals(expectedLocs, pong.getAltLocs()); Set<IpPort> expectedTLS = new IpPortSet(new IpPortImpl("5.6.7.8:9"), new IpPortImpl("6.7.8.9:10")); for(IpPort ipp : pong.getAltLocs()) { if(ipp instanceof Connectable && ((Connectable)ipp).isTLSCapable()) assertTrue(expectedTLS.remove(ipp)); } assertTrue("still had: " + expectedTLS, expectedTLS.isEmpty()); Set<PushEndpoint> pushLocs = pong.getPushLocs(); assertEquals(2, pushLocs.size()); Iterator<PushEndpoint> peIterator = pushLocs.iterator(); PushEndpoint read1 = peIterator.next(); PushEndpoint read2 = peIterator.next(); assertFalse(peIterator.hasNext()); PushEndpoint m1, m2; // figure out which order the set put the PEs in... if(Arrays.equals(read1.getClientGUID(), g1)) { m1 = read1; m2 = read2; } else { m1 = read2; m2 = read1; } assertEquals(g1, m1.getClientGUID()); assertEquals(g2, m2.getClientGUID()); assertEquals(1, m1.getProxies().size()); assertEquals(2, m2.getProxies().size()); assertTrue(pong.isTLSCapable()); assertEquals("SAMB", pong.getVendor()); assertFalse(pong.isFirewalled()); assertEquals(-1, pong.getQueueStatus()); assertFalse(pong.isBusy()); assertTrue(pong.isDownloading()); assertFalse(pong.isRoutingBroken()); // Just a quick test, since we already have the output stream built up, to make // sure binary won't work if version < 2 try { headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 1, out.toByteArray(), Network.UNKNOWN); fail("expected bpe!"); } catch(BadPacketException expected) {} } public void testHigherVersionGGEP() throws Exception { PushEndpointFactory pushEndpointFactory = injector.getInstance(PushEndpointFactory.class); GGEP ggep = new GGEP(); ggep.put("F", (byte)0x1); // TLS capable. ggep.put("C", (byte)0x2 | 0x8); // response code (partial, downloading) ggep.put("V", new byte[] { 'S', 'A', 'M', 'B' } ); // vendor ggep.put("Q", (byte)-1); // queue status. byte[] ranges = new byte[24]; ByteUtils.int2beb(1, ranges, 0); ByteUtils.int2beb(1000, ranges, 4); ByteUtils.int2beb(1050, ranges, 8); ByteUtils.int2beb(2001, ranges, 12); ByteUtils.int2beb(2500, ranges, 16); ByteUtils.int2beb(2525, ranges, 20); ggep.put("R", ranges); // ranges Random random = new Random(); byte[] g1 = new byte[16]; random.nextBytes(g1); PushEndpoint p1 = pushEndpointFactory.createPushEndpoint(g1, new IpPortSet(new IpPortImpl("1.2.3.4:5")), PushEndpoint.PLAIN, 0); byte[] p1b = p1.toBytes(false); byte[] g2 = new byte[16]; random.nextBytes(g2); PushEndpoint p2 = pushEndpointFactory.createPushEndpoint(g2, new IpPortSet(new IpPortImpl("2.3.4.5:6"), new IpPortImpl("3.4.5.6:7")), PushEndpoint.PLAIN, 0); byte[] p2b = p2.toBytes(false); byte[] pushbytes = new byte[p1b.length + p2b.length]; System.arraycopy(p1b, 0, pushbytes, 0, p1b.length); System.arraycopy(p2b, 0, pushbytes, p1b.length, p2b.length); ggep.put("P", pushbytes); // push locations. ggep.put("A", new byte[] { 4, 5, 6, 7, 8, 0, 5, 6, 7, 8, 9, 0, 6, 7, 8, 9, 10, 0 } ); // alternate locations ggep.put("T", new byte[] { 0x60 } ); // TLS indexes into alternate locations ByteArrayOutputStream out = new ByteArrayOutputStream(); ggep.write(out); HeadPong pong = headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 3, out.toByteArray(), Network.UNKNOWN); assertTrue(pong.hasFile()); assertFalse(pong.hasCompleteFile()); Iterator<Range> iterator = pong.getRanges().iterator(); assertEquals(Range.createRange(1, 1000), iterator.next()); assertEquals(Range.createRange(1050, 2001), iterator.next()); assertEquals(Range.createRange(2500, 2525), iterator.next()); assertFalse(iterator.hasNext()); Set<IpPort> expectedLocs = new IpPortSet(new IpPortImpl("4.5.6.7:8"), new IpPortImpl("5.6.7.8:9"), new IpPortImpl("6.7.8.9:10")); assertEquals(expectedLocs, pong.getAltLocs()); Set<IpPort> expectedTLS = new IpPortSet(new IpPortImpl("5.6.7.8:9"), new IpPortImpl("6.7.8.9:10")); for(IpPort ipp : pong.getAltLocs()) { if(ipp instanceof Connectable && ((Connectable)ipp).isTLSCapable()) assertTrue(expectedTLS.remove(ipp)); } assertTrue(expectedTLS.isEmpty()); Set<PushEndpoint> pushLocs = pong.getPushLocs(); assertEquals(2, pushLocs.size()); Iterator<PushEndpoint> peIterator = pushLocs.iterator(); PushEndpoint read1 = peIterator.next(); PushEndpoint read2 = peIterator.next(); assertFalse(peIterator.hasNext()); PushEndpoint m1, m2; // figure out which order the set put the PEs in... if(Arrays.equals(read1.getClientGUID(), g1)) { m1 = read1; m2 = read2; } else { m1 = read2; m2 = read1; } assertEquals(g1, m1.getClientGUID()); assertEquals(g2, m2.getClientGUID()); assertEquals(1, m1.getProxies().size()); assertEquals(2, m2.getProxies().size()); assertTrue(pong.isTLSCapable()); assertEquals("SAMB", pong.getVendor()); assertFalse(pong.isFirewalled()); assertEquals(-1, pong.getQueueStatus()); assertFalse(pong.isBusy()); assertTrue(pong.isDownloading()); assertFalse(pong.isRoutingBroken()); } public void testGGEP404() throws Exception { GGEP ggep = new GGEP(); ggep.put("C", (byte)0); ByteArrayOutputStream out = new ByteArrayOutputStream(); ggep.write(out); HeadPong pong = headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, out.toByteArray(), Network.UNKNOWN); assertFalse(pong.hasFile()); assertNull(pong.getRanges()); assertNull(pong.getVendor()); assertEmpty(pong.getAltLocs()); assertEmpty(pong.getPushLocs()); assertFalse(pong.isBusy()); assertFalse(pong.hasCompleteFile()); assertFalse(pong.isDownloading()); assertFalse(pong.isFirewalled()); assertFalse(pong.isRoutingBroken()); assertEquals(0, pong.getQueueStatus()); } public void testOldRoutingBrokenClientsAreMarked() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(HeadPing.GGEP_PING); // old client didn't unmask the GGEP Ping flag. out.write(0); // 404. HeadPong pong = headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 1, out.toByteArray(), Network.UNKNOWN); assertTrue(pong.isRoutingBroken()); } public void testTLSCapableAndUnknownFeatures() throws Exception { GGEP ggep = new GGEP(); // required fields. ggep.put("C", (byte)0x1); ggep.put("V", new byte[4]); ggep.put("Q", (byte)0); ggep.put("F", (byte)0xFF); // tls capable + a lot of unknown fields HeadPong pong = headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, arrayof(ggep), Network.UNKNOWN); assertTrue(pong.isTLSCapable()); } public void testNotTLSCapableButOtherFeatures() throws Exception { GGEP ggep = new GGEP(); // required fields. ggep.put("C", (byte)0x1); ggep.put("V", new byte[4]); ggep.put("Q", (byte)0); ggep.put("F", (byte)~0x1); // every feature but TLS capable HeadPong pong = headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, arrayof(ggep), Network.UNKNOWN); assertFalse(pong.isTLSCapable()); } public void testNotTLSCapableBecauseOfLackOfFeatureKey() throws Exception { GGEP ggep = new GGEP(); // required fields. ggep.put("C", (byte)0x1); ggep.put("V", new byte[4]); ggep.put("Q", (byte)0); HeadPong pong = headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, arrayof(ggep), Network.UNKNOWN); assertFalse(pong.isTLSCapable()); } public void testQueueRequired() throws Exception { GGEP ggep = new GGEP(); // required fields. ggep.put("C", (byte)0x1); ggep.put("V", new byte[4]); try { headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, arrayof(ggep), Network.UNKNOWN); fail("expected exception!"); } catch(BadPacketException bpe) {} } public void testVendorRequired() throws Exception { GGEP ggep = new GGEP(); // required fields. ggep.put("C", (byte)0x1); ggep.put("Q", (byte)0); try { headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, arrayof(ggep), Network.UNKNOWN); fail("expected exception!"); } catch(BadPacketException bpe) {} } public void testCodeRequired() throws Exception { GGEP ggep = new GGEP(); // required fields. ggep.put("V", new byte[4]); ggep.put("Q", (byte)0); try { headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, arrayof(ggep), Network.UNKNOWN); fail("expected exception!"); } catch(BadPacketException bpe) {} } public void testEmptyQueueFails() throws Exception { GGEP ggep = new GGEP(); // required fields. ggep.put("C", (byte)0x1); ggep.put("V", new byte[4]); ggep.put("Q", new byte[0]); try { headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, arrayof(ggep), Network.UNKNOWN); fail("expected exception!"); } catch(BadPacketException bpe) {} } public void testEmptyVendorFails() throws Exception { GGEP ggep = new GGEP(); // required fields. ggep.put("C", (byte)0x1); ggep.put("V", new byte[0]); ggep.put("Q", (byte)0); try { headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, arrayof(ggep), Network.UNKNOWN); fail("expected exception!"); } catch(BadPacketException bpe) {} } public void testEmptyCodeFails() throws Exception { GGEP ggep = new GGEP(); // required fields. ggep.put("C", new byte[0]); ggep.put("V", new byte[4]); ggep.put("Q", (byte)0); try { headPongFactory.createFromNetwork(new byte[16], (byte)0, (byte)0, 2, arrayof(ggep), Network.UNKNOWN); fail("expected exception!"); } catch(BadPacketException bpe) {} } public void testWriteBasicGGEPHeadPong() throws Exception { byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); networkManager.setIncomingTLSEnabled(false); networkManager.setAcceptedIncomingConnection(true); FileDescStub fd = new FileDescStub("file", UrnHelper.SHA1, 0); gnutellaFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x1 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWriteTLS() throws Exception { NetworkManagerStub networkManager = (NetworkManagerStub)injector.getInstance(NetworkManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); networkManager.setIncomingTLSEnabled(true); networkManager.setAcceptedIncomingConnection(true); networkManager.setTls(true); networkManager.setIncomingTLSEnabled(true); networkManager.setOutgoingTLSEnabled(true); FileDescStub fd = new FileDescStub("file", UrnHelper.SHA1, 0); gnutellaFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 4, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x1 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); assertEquals(new byte[] { 0x1 }, writtenGGEP.getBytes("F")); } public void testFirewalledBitAndDoesntWriteTLSIfFirewalled() throws Exception { NetworkManagerStub networkManager = (NetworkManagerStub)injector.getInstance(NetworkManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); networkManager.setIncomingTLSEnabled(true); networkManager.setAcceptedIncomingConnection(false); FileDescStub fd = new FileDescStub("file", UrnHelper.SHA1, 0); gnutellaFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x1 | 0x4 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWritingFNF() throws Exception { byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(GnutellaFileCollectionStub.DEFAULT_URN); req.setGuid(guid); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 1, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x0 }, writtenGGEP.getBytes("C")); } public void testWritingIncompleteCode() throws Exception { byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWritingIncompleteAndDownloadingCode() throws Exception { byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(true)); }}); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 | 0x8 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWriteBusyQueueStatus() throws Exception { UploadManagerStub uploadManager = (UploadManagerStub)injector.getInstance(UploadManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); FileDescStub fd = new FileDescStub("file", UrnHelper.SHA1, 0); gnutellaFileCollection.add(fd); uploadManager.setNumQueuedUploads(UploadSettings.UPLOAD_QUEUE_SIZE.getValue()); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x1 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { 0x7F }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWriteCorrectQueueStatus() throws Exception { UploadManagerStub uploadManager = (UploadManagerStub)injector.getInstance(UploadManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); FileDescStub fd = new FileDescStub("file", UrnHelper.SHA1, 0); gnutellaFileCollection.add(fd); uploadManager.setNumQueuedUploads(3); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x1 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { 3 }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWriteCorrectUploadsInProgressQueueStatus() throws Exception { UploadManagerStub uploadManager = (UploadManagerStub)injector.getInstance(UploadManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); FileDescStub fd = new FileDescStub("file", UrnHelper.SHA1, 0); gnutellaFileCollection.add(fd); uploadManager.setUploadsInProgress(UploadSettings.HARD_MAX_UPLOADS.getValue()-5); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x1 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { -5 }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWriteRanges() throws Exception { byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsRanges(true); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(Range.createRange(0, 500), Range.createRange(705, 1000), Range.createRange(20000, 25000)); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 4, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); byte[] ranges = writtenGGEP.getBytes("R"); assertEquals(0, ByteUtils.beb2int(ranges, 0)); assertEquals(500, ByteUtils.beb2int(ranges, 4)); assertEquals(705, ByteUtils.beb2int(ranges, 8)); assertEquals(1000, ByteUtils.beb2int(ranges, 12)); assertEquals(20000, ByteUtils.beb2int(ranges, 16)); assertEquals(25000, ByteUtils.beb2int(ranges, 20)); assertEquals(24, ranges.length); } public void testWriteLongRanges() throws Exception { byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsRanges(true); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(Range.createRange(0, 500), Range.createRange(0xFFFFFFFF00l, 0xFFFFFFFFFFl)); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 5, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); byte[] ranges = writtenGGEP.getBytes("R"); assertEquals(8, ranges.length); assertEquals(0, ByteUtils.beb2int(ranges, 0)); assertEquals(500, ByteUtils.beb2int(ranges, 4)); byte[] ranges5 = writtenGGEP.getBytes("R5"); assertEquals(10, ranges5.length); assertEquals(0xFFFFFFFF00l, ByteUtils.beb2long(ranges5, 0, 5)); assertEquals(0xFFFFFFFFFFl, ByteUtils.beb2long(ranges5, 5, 5)); // try only long ranges now fd.setRangesAsIntervals(Range.createRange(0xFFFFFFFF00l, 0xFFFFFFFFFFl)); pong = headPongFactory.create(req); out = new ByteArrayOutputStream(); pong.write(out); written = out.toByteArray(); writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); // there should not be an R extention try { writtenGGEP.getBytes("R"); fail("there was an R extention with only long ranges"); } catch (BadGGEPPropertyException expected){} ranges5 = writtenGGEP.getBytes("R5"); assertEquals(10, ranges5.length); assertEquals(0xFFFFFFFF00l, ByteUtils.beb2long(ranges5, 0, 5)); assertEquals(0xFFFFFFFFFFl, ByteUtils.beb2long(ranges5, 5, 5)); } public void testWriteRangesOnlyIfRequested() throws Exception { byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsRanges(false); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(Range.createRange(0, 500), Range.createRange(705, 1000), Range.createRange(20000, 25000)); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWriteBusyIfRangeRequestedButHasNone() throws Exception { byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsRanges(true); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(); incompleteFileCollection.add(fd); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { 0x7F }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWriteDoesntMakeBusyIfNoRangesButNotRequested() throws Exception { byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsRanges(false); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); HeadPong pong = headPongFactory.create(req); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWritesPushWithTLSWithFWTLocations() throws Exception { PushEndpointFactory pushEndpointFactory = injector.getInstance(PushEndpointFactory.class); AlternateLocationFactory alternateLocationFactory = injector.getInstance(AlternateLocationFactory.class); AltLocManager altLocManager = injector.getInstance(AltLocManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsPushLocs(true); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); GUID peGUID = new GUID(GUID.makeGuid()); PushAltLoc firewalled = (PushAltLoc) alternateLocationFactory.create(peGUID.toHexString()+";1.2.3.4:5", UrnHelper.SHA1); firewalled.updateProxies(true); altLocManager.add(firewalled, null); GUID peTlsGUID = new GUID(); PushAltLoc tls = (PushAltLoc) alternateLocationFactory.create(peTlsGUID.toHexString() + ";pptls=6;2.3.4.5:5;3.4.5.6:7;4.5.6.7:8", UrnHelper.SHA1); tls.updateProxies(true); altLocManager.add(tls, null); GUID peFwtGUID = new GUID(); PushAltLoc fwt = (PushAltLoc)alternateLocationFactory.create(peFwtGUID.toHexString() + ";fwt/1.0;10:20.21.23.23;pptls=8;2.3.4.5:5;3.4.5.6:7;4.5.6.7:8", UrnHelper.SHA1); fwt.updateProxies(true); altLocManager.add(fwt, null); HeadPong pong = headPongFactory.create(req); altLocManager.purge(); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 4, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); byte[] pushes = writtenGGEP.get("P"); DataInputStream in = new DataInputStream(new ByteArrayInputStream(pushes)); PushEndpoint pe1 = pushEndpointFactory.createFromBytes(in); PushEndpoint pe2 = pushEndpointFactory.createFromBytes(in); PushEndpoint pe3 = pushEndpointFactory.createFromBytes(in); assertEquals(0, in.available()); assertEquals(-1, in.read()); // Make sure it went in round-robin order for writing. assertEquals(0, pe1.getFWTVersion()); assertEquals(1, pe2.getFWTVersion()); assertEquals(0, pe3.getFWTVersion()); // Ok, it's easy enough to test the FWT one, since there's only one. assertEquals(peFwtGUID.bytes(), pe2.getClientGUID()); assertEquals("20.21.23.23", pe2.getAddress()); assertEquals(10, pe2.getPort()); Set<? extends IpPort> proxies = pe2.getProxies(); Set<IpPort> expectedNormalProxies = new IpPortSet(new IpPortImpl("3.4.5.6:7"), new IpPortImpl("4.5.6.7:8")); Set<IpPort> expectedTLSProxies = new IpPortSet(new IpPortImpl("2.3.4.5:5")); Set<IpPort> copy = new IpPortSet(proxies); assertEquals(3, proxies.size()); copy.retainAll(expectedNormalProxies); assertEquals(expectedNormalProxies, copy); for(IpPort ipp : copy) { if(ipp instanceof Connectable) assertFalse(((Connectable)ipp).isTLSCapable()); } copy = new IpPortSet(proxies); copy.retainAll(expectedTLSProxies); assertEquals(expectedTLSProxies, copy); for(IpPort ipp : copy) { assertInstanceof(Connectable.class, ipp); assertTrue(((Connectable)ipp).isTLSCapable()); } copy = new IpPortSet(proxies); copy.removeAll(expectedNormalProxies); copy.removeAll(expectedTLSProxies); assertEquals(0, copy.size()); // Setup so that pe1 is peGUID && pe3 == tlsGUID if(!Arrays.equals(pe1.getClientGUID(), peGUID.bytes())) { PushEndpoint tmp = pe1; pe1 = pe3; pe3 = tmp; } assertEquals(pe1.getClientGUID(), peGUID.bytes()); assertEquals(pe3.getClientGUID(), peTlsGUID.bytes()); // PE1 only has 1 proxy, and it's not TLS capable. proxies = pe1.getProxies(); assertEquals(1, proxies.size()); IpPort proxy = proxies.iterator().next(); assertEquals("1.2.3.4", proxy.getAddress()); assertEquals(5, proxy.getPort()); if(proxy instanceof Connectable) assertFalse(((Connectable)proxy).isTLSCapable()); // PE3 has 3 proxies, two of which are TLS capable. proxies = pe3.getProxies(); expectedTLSProxies = new IpPortSet(new IpPortImpl("3.4.5.6:7"), new IpPortImpl("4.5.6.7:8")); expectedNormalProxies = new IpPortSet(new IpPortImpl("2.3.4.5:5")); copy = new IpPortSet(proxies); assertEquals(3, proxies.size()); copy.retainAll(expectedNormalProxies); assertEquals(expectedNormalProxies, copy); for(IpPort ipp : copy) { if(ipp instanceof Connectable) assertFalse(((Connectable)ipp).isTLSCapable()); } copy = new IpPortSet(proxies); copy.retainAll(expectedTLSProxies); assertEquals(expectedTLSProxies, copy); for(IpPort ipp : copy) { assertInstanceof(Connectable.class, ipp); assertTrue(((Connectable)ipp).isTLSCapable()); } copy = new IpPortSet(proxies); copy.removeAll(expectedNormalProxies); copy.removeAll(expectedTLSProxies); assertEquals(0, copy.size()); } public void testWrittenFWTOnly() throws Exception { PushEndpointFactory pushEndpointFactory = injector.getInstance(PushEndpointFactory.class); AlternateLocationFactory alternateLocationFactory = injector.getInstance(AlternateLocationFactory.class); AltLocManager altLocManager = injector.getInstance(AltLocManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsPushLocs(true); req.setRequestsFWTOnlyPushLocs(true); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); GUID peGUID = new GUID(GUID.makeGuid()); PushAltLoc firewalled = (PushAltLoc)alternateLocationFactory.create(peGUID.toHexString()+";1.2.3.4:5", UrnHelper.SHA1); firewalled.updateProxies(true); altLocManager.add(firewalled, null); GUID peTlsGUID = new GUID(); PushAltLoc tls = (PushAltLoc)alternateLocationFactory.create(peTlsGUID.toHexString() + ";pptls=6;2.3.4.5:5;3.4.5.6:7;4.5.6.7:8", UrnHelper.SHA1); tls.updateProxies(true); altLocManager.add(tls, null); GUID peFwtGUID = new GUID(); PushAltLoc fwt = (PushAltLoc)alternateLocationFactory.create(peFwtGUID.toHexString() + ";fwt/1.0;10:20.21.23.23;pptls=8;2.3.4.5:5;3.4.5.6:7;4.5.6.7:8", UrnHelper.SHA1); fwt.updateProxies(true); altLocManager.add(fwt, null); HeadPong pong = headPongFactory.create(req); altLocManager.purge(); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 4, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); byte[] pushes = writtenGGEP.get("P"); DataInputStream in = new DataInputStream(new ByteArrayInputStream(pushes)); PushEndpoint pe1 = pushEndpointFactory.createFromBytes(in); assertEquals(0, in.available()); assertEquals(-1, in.read()); assertEquals(1, pe1.getFWTVersion()); assertEquals(peFwtGUID.bytes(), pe1.getClientGUID()); assertEquals("20.21.23.23", pe1.getAddress()); assertEquals(10, pe1.getPort()); Set<? extends IpPort> proxies = pe1.getProxies(); Set<IpPort> expectedNormalProxies = new IpPortSet(new IpPortImpl("3.4.5.6:7"), new IpPortImpl("4.5.6.7:8")); Set<IpPort> expectedTLSProxies = new IpPortSet(new IpPortImpl("2.3.4.5:5")); Set<IpPort> copy = new IpPortSet(proxies); assertEquals(3, proxies.size()); copy.retainAll(expectedNormalProxies); assertEquals(expectedNormalProxies, copy); for(IpPort ipp : copy) { if(ipp instanceof Connectable) assertFalse(((Connectable)ipp).isTLSCapable()); } copy = new IpPortSet(proxies); copy.retainAll(expectedTLSProxies); assertEquals(expectedTLSProxies, copy); for(IpPort ipp : copy) { assertInstanceof(Connectable.class, ipp); assertTrue(((Connectable)ipp).isTLSCapable()); } copy = new IpPortSet(proxies); copy.removeAll(expectedNormalProxies); copy.removeAll(expectedTLSProxies); assertEquals(0, copy.size()); } public void testNoPushWrittenIfNotRequested() throws Exception { AlternateLocationFactory alternateLocationFactory = injector.getInstance(AlternateLocationFactory.class); AltLocManager altLocManager = injector.getInstance(AltLocManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsPushLocs(false); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); GUID peFwtGUID = new GUID(); PushAltLoc fwt = (PushAltLoc)alternateLocationFactory.create(peFwtGUID.toHexString() + ";fwt/1.0;10:20.21.23.23;pptls=8;2.3.4.5:5;3.4.5.6:7;4.5.6.7:8", UrnHelper.SHA1); fwt.updateProxies(true); altLocManager.add(fwt, null); HeadPong pong = headPongFactory.create(req); altLocManager.purge(); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testNoPushWrittenIfNotRequestedEvenIfFWTOnlyRequested() throws Exception { AlternateLocationFactory alternateLocationFactory = injector.getInstance(AlternateLocationFactory.class); AltLocManager altLocManager = injector.getInstance(AltLocManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsPushLocs(false); req.setRequestsFWTOnlyPushLocs(true); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); GUID peFwtGUID = new GUID(); PushAltLoc fwt = (PushAltLoc)alternateLocationFactory.create(peFwtGUID.toHexString() + ";fwt/1.0;10:20.21.23.23;pptls=8;2.3.4.5:5;3.4.5.6:7;4.5.6.7:8", UrnHelper.SHA1); fwt.updateProxies(true); altLocManager.add(fwt, null); HeadPong pong = headPongFactory.create(req); altLocManager.purge(); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWriteDirectLocs() throws Exception { AlternateLocationFactory alternateLocationFactory = injector.getInstance(AlternateLocationFactory.class); AltLocManager altLocManager = injector.getInstance(AltLocManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsAltLocs(true); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); for(int i=0;i<10;i++ ) { AlternateLocation al = alternateLocationFactory.create("1.2.3."+i+":1234", UrnHelper.SHA1); altLocManager.add(al, null); } HeadPong pong = headPongFactory.create(req); altLocManager.purge(); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 4, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); byte[] locs = writtenGGEP.getBytes("A"); assertEquals(60, locs.length); Collection<IpPort> ipps = NetworkUtils.unpackIps(locs); assertEquals(10, ipps.size()); Set<Byte> dots = new TreeSet<Byte>(); for(IpPort ipp : ipps) { assertTrue(ipp.getAddress().startsWith("1.2.3.")); assertEquals(1234, ipp.getPort()); dots.add(ipp.getInetAddress().getAddress()[3]); } assertEquals(10, dots.size()); Iterator<Byte> octects = dots.iterator(); assertEquals(0, (int)octects.next()); assertEquals(1, (int)octects.next()); assertEquals(2, (int)octects.next()); assertEquals(3, (int)octects.next()); assertEquals(4, (int)octects.next()); assertEquals(5, (int)octects.next()); assertEquals(6, (int)octects.next()); assertEquals(7, (int)octects.next()); assertEquals(8, (int)octects.next()); assertEquals(9, (int)octects.next()); } public void testNotWriteDirectLocsIfNotRequested() throws Exception { AlternateLocationFactory alternateLocationFactory = injector.getInstance(AlternateLocationFactory.class); AltLocManager altLocManager = injector.getInstance(AltLocManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsAltLocs(false); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); for(int i=0;i<10;i++ ) { AlternateLocation al = alternateLocationFactory.create("1.2.3."+i+":1234", UrnHelper.SHA1); altLocManager.add(al, null); } HeadPong pong = headPongFactory.create(req); altLocManager.purge(); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 3, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); } public void testWriteTLSWithLocs() throws Exception { AlternateLocationFactory alternateLocationFactory = injector.getInstance(AlternateLocationFactory.class); AltLocManager altLocManager = injector.getInstance(AltLocManager.class); byte[] guid = new byte[16]; Random r = new Random(); r.nextBytes(guid); MockHeadPongRequestor req = new MockHeadPongRequestor(); req.setPongGGEPCapable(true); req.setUrn(UrnHelper.SHA1); req.setGuid(guid); req.setRequestsAltLocs(true); final IncompleteFileDescStub fd = new IncompleteFileDescStub("test", UrnHelper.SHA1, 100); fd.setRangesAsIntervals(); incompleteFileCollection.add(fd); int expectedUploads = -UploadSettings.HARD_MAX_UPLOADS.getValue(); mockery.checking(new Expectations() {{ atLeast(1).of(downloadManager).isActivelyDownloading(with(same(fd.getSHA1Urn()))); will(returnValue(false)); }}); for(int i=0;i<10;i++ ) { AlternateLocation al = alternateLocationFactory.create("1.2.3."+i+":1234", UrnHelper.SHA1, i % 2 == 0); altLocManager.add(al, null); } HeadPong pong = headPongFactory.create(req); altLocManager.purge(); ByteArrayOutputStream out = new ByteArrayOutputStream(); pong.write(out); byte[] written = out.toByteArray(); assertEquals(guid, written, 0, 16); // 16...23, rest of Gnutella header, ignore. assertEquals("LIME", StringUtils.getASCIIString(written, 23, 4)); // headpong vendor ID assertEquals(24, ByteUtils.leb2short(written, 27)); // headpong selector assertEquals(2, ByteUtils.leb2short(written, 29)); // current headpong version int[] endOffset = new int[1]; GGEP writtenGGEP = new GGEP(written, 31, endOffset); assertEquals(written.length, endOffset[0]); assertEquals("got headers: " + writtenGGEP.getHeaders(), 5, writtenGGEP.getHeaders().size()); assertEquals(new byte[] { 0x2 }, writtenGGEP.getBytes("C")); assertEquals(new byte[] { (byte)expectedUploads }, writtenGGEP.getBytes("Q")); assertEquals(StringUtils.toAsciiBytes("LIME"), writtenGGEP.getBytes("V")); byte[] locs = writtenGGEP.getBytes("A"); assertEquals(60, locs.length); Collection<IpPort> ipps = NetworkUtils.unpackIps(locs); assertEquals(10, ipps.size()); // rebuild bitnumbers to get an expected TLS array, // since the IPs could have been sent in any order. Set<Byte> dots = new TreeSet<Byte>(); BitNumbers bn = new BitNumbers(10); int i = 0; for(IpPort ipp : ipps) { assertTrue(ipp.getAddress().startsWith("1.2.3.")); assertEquals(1234, ipp.getPort()); byte b = ipp.getInetAddress().getAddress()[3]; dots.add(b); if(b % 2 == 0) bn.set(i); i++; } // make sure what we expect TLS to be is what it is. assertEquals(bn.toByteArray(), writtenGGEP.getBytes("T")); // Make sure we actually got the right IPs! assertEquals(10, dots.size()); Iterator<Byte> octects = dots.iterator(); assertEquals(0, (int)octects.next()); assertEquals(1, (int)octects.next()); assertEquals(2, (int)octects.next()); assertEquals(3, (int)octects.next()); assertEquals(4, (int)octects.next()); assertEquals(5, (int)octects.next()); assertEquals(6, (int)octects.next()); assertEquals(7, (int)octects.next()); assertEquals(8, (int)octects.next()); assertEquals(9, (int)octects.next()); } private byte[] arrayof(GGEP ggep) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); ggep.write(out); return out.toByteArray(); } }