package com.limegroup.gnutella.messages;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.InetAddress;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ScheduledExecutorService;
import junit.framework.Test;
import org.limewire.io.GGEP;
import org.limewire.io.GUID;
import org.limewire.io.IpPort;
import org.limewire.io.IpPortImpl;
import org.limewire.io.NetworkInstanceUtils;
import org.limewire.net.ConnectionDispatcher;
import org.limewire.net.SocketsManager;
import org.limewire.security.AddressSecurityToken;
import org.limewire.security.MACCalculatorRepositoryManager;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.limegroup.gnutella.ConnectionManager;
import com.limegroup.gnutella.ConnectionManagerImpl;
import com.limegroup.gnutella.ConnectionServices;
import com.limegroup.gnutella.Endpoint;
import com.limegroup.gnutella.ExtendedEndpoint;
import com.limegroup.gnutella.HostCatcher;
import com.limegroup.gnutella.LimeTestUtils;
import com.limegroup.gnutella.NetworkManager;
import com.limegroup.gnutella.NodeAssigner;
import com.limegroup.gnutella.QueryUnicaster;
import com.limegroup.gnutella.connection.ConnectionCheckerManager;
import com.limegroup.gnutella.connection.RoutedConnectionFactory;
import com.limegroup.gnutella.filters.IPFilter;
import com.limegroup.gnutella.messages.Message.Network;
import com.limegroup.gnutella.messages.vendor.CapabilitiesVMFactory;
import com.limegroup.gnutella.simpp.SimppManager;
import com.limegroup.gnutella.stubs.NetworkManagerStub;
import com.limegroup.gnutella.util.LimeTestCase;
@SuppressWarnings( { "unchecked", "cast" } )
public class PingReplyTest extends LimeTestCase {
/**
* A non blank IP
*/
private final byte[] IP = new byte[] { 1, 1, 1, 1 };
private PingReplyFactory pingReplyFactory;
private MessageFactory messageFactory;
private NetworkManagerStub networkManagerStub;
private HostCatcher hostCatcher;
private TestConnectionManager testConnectionManager;
private MACCalculatorRepositoryManager macManager;
public PingReplyTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(PingReplyTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
@Override
protected void setUp() throws Exception {
networkManagerStub = new NetworkManagerStub();
networkManagerStub.setPort(5555);
networkManagerStub.setAddress(new byte[] { 89, 1, 45, 54 }) ;
networkManagerStub.setTls(true);
networkManagerStub.setIncomingTLSEnabled(true);
networkManagerStub.setOutgoingTLSEnabled(true);
Injector injector = LimeTestUtils.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(NetworkManager.class).toInstance(networkManagerStub);
bind(ConnectionManager.class).to(TestConnectionManager.class);
}
});
pingReplyFactory = injector.getInstance(PingReplyFactory.class);
messageFactory = injector.getInstance(MessageFactory.class);
hostCatcher = injector.getInstance(HostCatcher.class);
testConnectionManager = (TestConnectionManager) injector.getInstance(ConnectionManager.class);
macManager = injector.getInstance(MACCalculatorRepositoryManager.class);
}
/**
* Tests the methods for getting the leaf and ultrapeer slots from the
* pong.
*
* @throws Exception if an error occurs
*/
public void testHasFreeSlots() throws Exception {
byte[] guid = GUID.makeGuid();
byte[] ip = {1,1,1,1};
PingReply pr = pingReplyFactory.create(guid, (byte)3, 6346, ip,
(long)10, (long)10, true, 100, true);
//All values are determined based on connection status, and because
// we haven't set up connections yet, we don't have free anything.
assertTrue("slots not empty", !pr.hasFreeSlots());
assertEquals("unexpected number leaf slots", 0, pr.getNumLeafSlots());
assertTrue("slots not empty", !pr.hasFreeLeafSlots());
assertTrue("slots not empty", !pr.hasFreeUltrapeerSlots());
assertEquals("slots not empty", 0, pr.getNumUltrapeerSlots());
// Switch ConnectionManager to report different values for free leaf
// and ultrapeer slots.
testConnectionManager.setNumFreeNonLeafSlots(7);
testConnectionManager.setNumFreeLeafSlots(10);
pr = pingReplyFactory.create(guid, (byte)3, 6346, ip,
(long)10, (long)10, true, 100, true);
assertTrue("no slots", pr.hasFreeSlots());
assertTrue("no slots", pr.hasFreeLeafSlots());
assertTrue("no slots", pr.hasFreeUltrapeerSlots());
// Should now have leaf slots
assertEquals("unexpected number leaf slots",
testConnectionManager.getNumFreeLimeWireLeafSlots(),
pr.getNumLeafSlots());
assertEquals("unexpected number ultrapeer slots",
testConnectionManager.getNumFreeLimeWireNonLeafSlots(),
pr.getNumUltrapeerSlots());
}
/**
* Tests the method for creating a new pong with a changed GUID out
* of an existing pong
*/
public void testMutateGUID() throws Exception {
byte[] guid = new GUID().bytes();
byte ttl = 4;
int port = 6444;
byte[] ip = {1, 1, 1, 1};
long files = 500L;
long kbytes = 75580L;
boolean isUltrapeer = false;
int dailyUptime = 10;
boolean isGUESSCapable = false;
PingReply pr =
pingReplyFactory.create(guid, ttl, port, ip, files, kbytes,
isUltrapeer, dailyUptime, isGUESSCapable);
PingReply testPR = pingReplyFactory.mutateGUID(pr, new GUID().bytes());
assertNotEquals(pr.getGUID(), testPR.getGUID());
assertEquals(pr.getTTL(), testPR.getTTL());
assertEquals(pr.getPort(), testPR.getPort());
assertEquals(pr.getInetAddress(), testPR.getInetAddress());
assertEquals(pr.getFiles(), testPR.getFiles());
assertEquals(pr.getKbytes(), testPR.getKbytes());
assertEquals(pr.isUltrapeer(), testPR.isUltrapeer());
assertEquals(pr.getDailyUptime(), testPR.getDailyUptime());
assertEquals(pr.supportsUnicast(), testPR.supportsUnicast());
}
/**
* Tests the method for creating a pong from the network.
*/
public void testCreatePongFromNetwork() throws Exception {
byte[] guid = new GUID().bytes();
byte[] payload = new byte[2];
// make sure we reject invalid payload sizes
try {
pingReplyFactory.createFromNetwork(guid, (byte)4, (byte)3,
payload);
fail("should have not accepted payload size");
} catch(BadPacketException e) {
// expected because the payload size is invalid
}
// make sure we reject null guids
payload = new byte[PingReply.STANDARD_PAYLOAD_SIZE];
addIP(payload);
try {
pingReplyFactory.createFromNetwork(null, (byte)4, (byte)3,
payload);
fail("should have not accepted null guid");
} catch(NullPointerException e) {
// expected because the payload size is invalid
}
// make sure we reject null payloads
try {
pingReplyFactory.createFromNetwork(guid, (byte)4, (byte)3,
null);
fail("should have not accepted null payload");
} catch(NullPointerException e) {
// expected because the payload size is invalid
}
// make sure we reject bad ggep
GGEP ggep = new GGEP();
payload = new byte[3];
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_IPPORTS, payload);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ggep.write(baos);
byte[] extensions = baos.toByteArray();
payload =
new byte[PingReply.STANDARD_PAYLOAD_SIZE+extensions.length];
addIP(payload);
System.arraycopy(extensions, 0,
payload, PingReply.STANDARD_PAYLOAD_SIZE,
extensions.length);
try {
pingReplyFactory.createFromNetwork(guid, (byte)4, (byte)3,
payload);
fail("should have not accepted bad GGEP in payload");
} catch(BadPacketException e) {
// expected because the payload size is invalid
}
// test one that should go through fine
payload = new byte[PingReply.STANDARD_PAYLOAD_SIZE];
payload[0] = 1;
addIP(payload);
// this one should go through
pingReplyFactory.createFromNetwork(guid, (byte)4, (byte)3,
payload);
}
public void testNewPong() {
long u4=0x00000000FFFFFFFFl;
int u2=0x0000FFFF;
byte[] ip={(byte)0xFE, (byte)0x00, (byte)0x00, (byte)0x1};
PingReply pr = pingReplyFactory.create(new byte[16], (byte)0,
u2, ip, u4, u4);
assertEquals(u2, pr.getPort());
assertEquals(u4, pr.getFiles());
long kbytes=pr.getKbytes();
assertEquals(Long.toHexString(kbytes), u4, kbytes);
String ip2=pr.getAddress();
assertEquals("254.0.0.1", ip2);
assertTrue(! pr.isUltrapeer());
}
//TODO: check construction from raw bytes
public void testPongMarking() {
PingReply pr =
pingReplyFactory.createExternal(new byte[16], (byte)2, 6346, IP,
false);
assertTrue(! pr.isUltrapeer());
// all pongs should have a GGEP extension now....
assertTrue("pong should have GGEP ext", pr.hasGGEPExtension());
pr = pingReplyFactory.createExternal(new byte[16], (byte)2, 6346, IP,
true);
assertTrue(pr.isUltrapeer());
// all pongs should have a GGEP extension now....
assertTrue("pong should have GGEP ext", pr.hasGGEPExtension());
pr = pingReplyFactory.create(new byte[16], (byte)2, 6346, IP,
5, 2348, false, 0, false);
assertTrue(! pr.isUltrapeer());
assertEquals(2348, pr.getKbytes());
// all pongs should have a GGEP extension now....
assertTrue("pong should have GGEP ext", pr.hasGGEPExtension());
pr = pingReplyFactory.create(new byte[16], (byte)2, 6346, IP,
5, 2348, true, 0, true);
assertTrue(pr.isUltrapeer());
// all pongs should have a GGEP extension now....
assertTrue("pong should have GGEP ext", pr.hasGGEPExtension());
pr = pingReplyFactory.create(new byte[16], (byte)2, 6346, IP,
5, 345882, false, 0, false);
assertTrue(! pr.isUltrapeer());
// all pongs should have a GGEP extension now....
assertTrue("pong should have GGEP ext", pr.hasGGEPExtension());
pr = pingReplyFactory.create(new byte[16], (byte)2, 6346, IP,
5, 345882, true, -1, true);
assertTrue(pr.isUltrapeer());
// after added unicast support, all Ultrapeer Pongs have GGEP extension
assertTrue("pong should have GGEP ext", pr.hasGGEPExtension());
assertEquals("pong should not have a daily uptime", -1,
pr.getDailyUptime());
}
public void testPowerOf2() {
assertTrue(! PingReplyImpl.isPowerOf2(-1));
assertTrue(! PingReplyImpl.isPowerOf2(0));
assertTrue(PingReplyImpl.isPowerOf2(1));
assertTrue(PingReplyImpl.isPowerOf2(2));
assertTrue(! PingReplyImpl.isPowerOf2(3));
assertTrue(PingReplyImpl.isPowerOf2(4));
assertTrue(PingReplyImpl.isPowerOf2(16));
assertTrue(! PingReplyImpl.isPowerOf2(18));
assertTrue(PingReplyImpl.isPowerOf2(64));
assertTrue(! PingReplyImpl.isPowerOf2(71));
}
public void testNonGGEPBigPong() throws Exception {
//Will this pass big pongs--even if the contents are not GGEP?
byte[] payload = new byte[14+2];
//add the port
payload[0] = 0x0F;
payload[1] = 0x00;//port
payload[2] = 0x10;
payload[3] = 0x10;
payload[4] = 0x10;
payload[5] = 0x10;//ip = 16.16.16.16
payload[6] = 0x0F;//
payload[7] = 0x00;//
payload[8] = 0x00;//
payload[9] = 0x00;//15 files shared
payload[10] = 0x0F;//
payload[11] = 0x00;//
payload[12] = 0x00;//
payload[13] = 0x00;//15 KB
//OK Now for the big pong part
payload[14] = (byte) 65;
payload[15] = (byte) 66;
PingReply pr;
pr = pingReplyFactory.createFromNetwork(new byte[16], (byte)2, (byte)4, payload);
assertTrue(! pr.hasGGEPExtension());
assertEquals("pong should not have a daily uptime", -1,
pr.getDailyUptime());
//Start testing
assertEquals("wrong port", 15, pr.getPort());
String ip = pr.getAddress();
assertEquals("wrong IP", "16.16.16.16", ip);
assertEquals("wrong files", 15, pr.getFiles());
assertEquals("Wrong share size", 15, pr.getKbytes());
ByteArrayOutputStream stream = new ByteArrayOutputStream();
pr.write(stream);
byte[] op = stream.toByteArray();
byte[] big = new byte[2];
big[0] = op[op.length-2];
big[1] = op[op.length-1];
String out = new String(big);
assertEquals("Big part of pong lost", "AB", out);
//come this far means its OK
}
public void testBasicGGEP() throws Exception {
networkManagerStub.setIncomingTLSEnabled(true);
// create a pong
PingReply pr =
pingReplyFactory.createExternal(new byte[16], (byte)3, 6349, IP, false);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
pr.write(baos);
byte[] bytes=baos.toByteArray();
//Decode and check contents.
Message m=messageFactory.read(new ByteArrayInputStream(bytes), Network.TCP);
PingReply pong=(PingReply)m;
assertTrue(m instanceof PingReply);
assertEquals(6349, pong.getPort());
assertTrue("pong should have GGEP ext", pr.hasGGEPExtension());
assertFalse(pong.supportsUnicast());
assertTrue(pong.isTLSCapable());
// make sure it's still capable if we turn our settings off.
networkManagerStub.setIncomingTLSEnabled(false);
assertTrue(pong.isTLSCapable());
// And try creating a new pong w/o TLS.
// create a pong
pr = pingReplyFactory.createExternal(new byte[16], (byte)3, 6349, IP, false);
baos.reset();
pr.write(baos);
bytes=baos.toByteArray();
m=messageFactory.read(new ByteArrayInputStream(bytes), Network.TCP);
pong=(PingReply)m;
assertFalse(pong.isTLSCapable());
// make sure it's still off if we turn our settings on.
networkManagerStub.setIncomingTLSEnabled(true);
assertFalse(pong.isTLSCapable());
}
/** Test the raw bytes of an encoded GGEP'ed pong. Then checks that
* these can be decoded. Note that this will need to be changed if
* more extensions are added. */
public void testGGEPEncodeDecode() throws Exception {
PingReply pr = pingReplyFactory.create(new byte[16], (byte)3, 6349, IP,
0l, 0l, true, 523, true);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
pr.write(baos);
byte[] bytes=baos.toByteArray();
int duLength=GGEPKeys.GGEP_HEADER_DAILY_AVERAGE_UPTIME.length();
int gueLength=GGEPKeys.GGEP_HEADER_UNICAST_SUPPORT.length();
int upLength=GGEPKeys.GGEP_HEADER_UP_SUPPORT.length();
int dhtLength = GGEPKeys.GGEP_HEADER_DHT_SUPPORT.length();
int tlsLength = GGEPKeys.GGEP_HEADER_TLS_CAPABLE.length();
int ggepLength=1 //magic number
+1 //"DUPTIME" extension flags
+duLength //ID
+1 //data length
+2 //data bytes
+1 //"GUE" extension flags
+gueLength // ID
+1 //data length
+0 //data bytes
+1 //"UP" extension flags
+upLength // ID
+1 // data length
+3 // data bytes
+1 //"DHT" extension flags
+dhtLength
+1 // data length
+3 // data bytes
+1 // "TLS" extension flags
+tlsLength // ID
+1; // EOGGEP.
assertEquals(23+14+ggepLength, bytes.length);
int offset=23+14; //GGEP offset
assertEquals((byte)0xc3, bytes[offset]); //GGEP magic number
assertEquals((byte)(dhtLength), bytes[offset+1]); //extension flags
assertEquals((byte)'D', bytes[offset+2]);
assertEquals((byte)'H', bytes[offset+3]);
assertEquals((byte)'T', bytes[offset+4]);
assertEquals((byte)'D', bytes[offset+2+dhtLength+5]);
assertEquals((byte)'U', bytes[offset+2+dhtLength+6]);
assertEquals((byte)0x0B, bytes[offset+2+dhtLength+8]); // little byte of 523
assertEquals((byte)0x02, bytes[offset+2+dhtLength+9]); // big byte of 523
assertEquals((byte)'G', bytes[offset+2+dhtLength+5+duLength+4]);
assertEquals((byte)'U', bytes[offset+2+dhtLength+5+duLength+5]);
assertEquals((byte)'E', bytes[offset+2+dhtLength+5+duLength+6]);
assertEquals((byte)'T', bytes[offset+2+dhtLength+5+duLength+4+gueLength+2]);
assertEquals((byte)'L', bytes[offset+2+dhtLength+5+duLength+4+gueLength+3]);
assertEquals((byte)'S', bytes[offset+2+dhtLength+5+duLength+4+gueLength+4]);
assertEquals((byte)'U', bytes[offset+2+dhtLength+5+duLength+4+gueLength+2+tlsLength+2]);
assertEquals((byte)'P', bytes[offset+2+dhtLength+5+duLength+4+gueLength+2+tlsLength+3]);
//Decode and check contents.
Message m=messageFactory.read(new ByteArrayInputStream(bytes), Network.TCP);
PingReply pong=(PingReply)m;
assertTrue(m instanceof PingReply);
assertEquals(6349, pong.getPort());
assertTrue("pong should have GGEP ext", pr.hasGGEPExtension());
assertEquals(523, pong.getDailyUptime());
assertTrue(pong.supportsUnicast());
assertTrue(pong.isTLSCapable());
}
/** Test the raw bytes of an encoded GGEP'ed pong. Then checks that
* these can be decoded. Note that this will need to be changed if
* more extensions are added. */
public void testGGEPEncodeDecodeNoGUESS() throws Exception {
PingReply pr=pingReplyFactory.create(new byte[16], (byte)3, 6349, IP,
0l, 0l, true, 523, false);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
pr.write(baos);
byte[] bytes=baos.toByteArray();
int duLength=GGEPKeys.GGEP_HEADER_DAILY_AVERAGE_UPTIME.length();
int upLength=GGEPKeys.GGEP_HEADER_UP_SUPPORT.length();
int dhtLength = GGEPKeys.GGEP_HEADER_DHT_SUPPORT.length();
int tlsLength = GGEPKeys.GGEP_HEADER_TLS_CAPABLE.length();
int ggepLength=1 //magic number
+1 //"DUPTIME" extension flags
+duLength //ID
+1 //data length
+2 //data bytes
+1 //"UP" extension flags
+upLength // ID
+1 // data length
+3 // data bytes
+1 //"DHT" extension flags
+dhtLength
+1 // data length
+3 // data bytes
+1 // "TLS" extension flags
+tlsLength // ID
+1; // EOGGEP.
assertEquals(23+14+ggepLength, bytes.length);
int offset=23+14; //GGEP offset
assertEquals((byte)0xc3, bytes[offset]); //GGEP magic number
assertEquals((byte)(dhtLength), bytes[offset+1]); //extension flags
assertEquals((byte)'D', bytes[offset+2]);
assertEquals((byte)'H', bytes[offset+3]);
assertEquals((byte)'T', bytes[offset+4]);
assertEquals((byte)'D', bytes[offset+2+dhtLength+5]);
assertEquals((byte)'U', bytes[offset+2+dhtLength+6]);
assertEquals((byte)0x0B, bytes[offset+2+dhtLength+8]); // little byte of 523
assertEquals((byte)0x02, bytes[offset+2+dhtLength+9]); // big byte of 523
assertEquals((byte)'T', bytes[offset+2+dhtLength+5+duLength+4]);
assertEquals((byte)'L', bytes[offset+2+dhtLength+5+duLength+5]);
assertEquals((byte)'S', bytes[offset+2+dhtLength+5+duLength+6]);
assertEquals((byte)'U', bytes[offset+2+dhtLength+5+duLength+4+tlsLength+2]);
assertEquals((byte)'P', bytes[offset+2+dhtLength+5+duLength+4+tlsLength+3]);
//Decode and check contents.
Message m=messageFactory.read(new ByteArrayInputStream(bytes), Network.TCP);
PingReply pong=(PingReply)m;
assertTrue(m instanceof PingReply);
assertEquals(6349, pong.getPort());
assertTrue("pong should have GGEP ext", pr.hasGGEPExtension());
assertEquals(523, pong.getDailyUptime());
assertFalse(pong.supportsUnicast());
assertTrue(pong.isTLSCapable());
}
/** Test the raw bytes of an encoded GGEP'ed pong. Then checks that
* these can be decoded. Note that this will need to be changed if
* more extensions are added. */
public void testGGEPEncodeDecodeNoTLS() throws Exception {
networkManagerStub.setIncomingTLSEnabled(false);
PingReply pr=pingReplyFactory.create(new byte[16], (byte)3, 6349, IP,
0l, 0l, true, 523, false);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
pr.write(baos);
byte[] bytes=baos.toByteArray();
int duLength=GGEPKeys.GGEP_HEADER_DAILY_AVERAGE_UPTIME.length();
int upLength=GGEPKeys.GGEP_HEADER_UP_SUPPORT.length();
int dhtLength = GGEPKeys.GGEP_HEADER_DHT_SUPPORT.length();
int ggepLength=1 //magic number
+1 //"DUPTIME" extension flags
+duLength //ID
+1 //data length
+2 //data bytes
+1 //"UP" extension flags
+upLength // ID
+1 // data length
+3 // data bytes
+1 //"DHT" extension flags
+dhtLength
+1 // data length
+3; // data bytes
assertEquals(23+14+ggepLength, bytes.length);
int offset=23+14; //GGEP offset
assertEquals((byte)0xc3, bytes[offset]); //GGEP magic number
assertEquals((byte)(dhtLength), bytes[offset+1]); //extension flags
assertEquals((byte)'D', bytes[offset+2]);
assertEquals((byte)'H', bytes[offset+3]);
assertEquals((byte)'T', bytes[offset+4]);
assertEquals((byte)'D', bytes[offset+2+dhtLength+5]);
assertEquals((byte)'U', bytes[offset+2+dhtLength+6]);
assertEquals((byte)0x0B, bytes[offset+2+dhtLength+8]); // little byte of 523
assertEquals((byte)0x02, bytes[offset+2+dhtLength+9]); // big byte of 523
assertEquals((byte)'U', bytes[offset+2+dhtLength+5+duLength+4]);
assertEquals((byte)'P', bytes[offset+2+dhtLength+5+duLength+5]);
//Decode and check contents.
Message m=messageFactory.read(new ByteArrayInputStream(bytes), Network.TCP);
PingReply pong=(PingReply)m;
assertTrue(m instanceof PingReply);
assertEquals(6349, pong.getPort());
assertTrue("pong should have GGEP ext", pr.hasGGEPExtension());
assertEquals(523, pong.getDailyUptime());
assertFalse(pong.supportsUnicast());
assertFalse(pong.isTLSCapable());
}
public void testPongTooSmall() throws Exception {
byte[] bytes=new byte[23+25]; //one byte too small
bytes[16]=Message.F_PING_REPLY;
bytes[17]=(byte)3; //hops
bytes[18]=(byte)3; //ttl
bytes[19]=(byte)13; //payload length
ByteArrayInputStream in=new ByteArrayInputStream(bytes);
try {
messageFactory.read(in, Network.TCP);
fail("No exception thrown");
} catch (BadPacketException pass) {
//Pass!
}
}
public void testQueryKeyPong() throws Exception {
byte[] randBytes = new byte[8];
(new Random()).nextBytes(randBytes);
AddressSecurityToken qk;
GUID guid = new GUID(GUID.makeGuid());
byte[] ip={(byte)18, (byte)239, (byte)3, (byte)144};
qk = new AddressSecurityToken(randBytes, macManager);
PingReply pr =
pingReplyFactory.createQueryKeyReply(guid.bytes(), (byte) 1, 6346, ip,
2, 2, true, qk);
assertTrue(pr.getQueryKey().equals(qk));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
pr.write(baos);
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
PingReply prStreamed = (PingReply) messageFactory.read(bais, Network.TCP);
assertTrue(prStreamed.getQueryKey().equals(qk));
}
public void testIpRequestPong() throws Exception {
networkManagerStub.setAddress(InetAddress.getLocalHost().getAddress());
// a pong carrying an ip:port
Endpoint e = new Endpoint("1.2.3.4",5);
PingReply p = pingReplyFactory.create(GUID.makeGuid(),(byte)1,e);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
p.write(baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
PingReply fromNet = (PingReply)messageFactory.read(bais, Network.TCP);
assertEquals("1.2.3.4",fromNet.getMyInetAddress().getHostAddress());
assertEquals(5,fromNet.getMyPort());
// a pong carrying invalid port
e = new Endpoint("1.2.3.4",5) {
@Override
public int getPort() {
return 0;
}
};
p = pingReplyFactory.create(GUID.makeGuid(),(byte)1,e);
baos = new ByteArrayOutputStream();
p.write(baos);
bais = new ByteArrayInputStream(baos.toByteArray());
fromNet = (PingReply)messageFactory.read(bais, Network.TCP);
assertNull(fromNet.getMyInetAddress());
assertEquals(0,fromNet.getMyPort());
//a pong carrying private ip
e = new Endpoint("192.168.0.1",20);
p = pingReplyFactory.create(GUID.makeGuid(),(byte)1,e);
baos = new ByteArrayOutputStream();
p.write(baos);
bais = new ByteArrayInputStream(baos.toByteArray());
fromNet = (PingReply)messageFactory.read(bais, Network.TCP);
assertNull(fromNet.getMyInetAddress());
assertEquals(0,fromNet.getMyPort());
// a pong not carrying ip:port
p = pingReplyFactory.create(GUID.makeGuid(),(byte)1);
baos = new ByteArrayOutputStream();
p.write(baos);
bais = new ByteArrayInputStream(baos.toByteArray());
fromNet = (PingReply)messageFactory.read(bais, Network.TCP);
assertNull(fromNet.getMyInetAddress());
assertEquals(0,fromNet.getMyPort());
}
public void testUDPHostCacheExtension() throws Exception {
GGEP ggep = new GGEP();
ggep.put(GGEPKeys.GGEP_HEADER_UDP_HOST_CACHE);
PingReply pr = pingReplyFactory.create(GUID.makeGuid(), (byte)1, 1,
new byte[] { 1, 1, 1, 1 },
(long)0, (long)0, false, ggep);
assertTrue(pr.isUDPHostCache());
assertEquals("1.1.1.1", pr.getUDPCacheAddress());
ByteArrayOutputStream out = new ByteArrayOutputStream();
pr.write(out);
byte[] b = out.toByteArray();
PingReply read = (PingReply)messageFactory.read(new ByteArrayInputStream(b), Network.TCP);
assertTrue(read.isUDPHostCache());
assertEquals("1.1.1.1", read.getUDPCacheAddress());
ggep = new GGEP();
ggep.put(GGEPKeys.GGEP_HEADER_UDP_HOST_CACHE, "www.nowhere.org");
pr = pingReplyFactory.create(GUID.makeGuid(), (byte)1, 1,
new byte[] { 1, 1, 1, 1 },
(long)0, (long)0, false, ggep);
assertTrue(pr.isUDPHostCache());
assertEquals("www.nowhere.org", pr.getUDPCacheAddress());
out = new ByteArrayOutputStream();
pr.write(out);
b = out.toByteArray();
read = (PingReply)messageFactory.read(new ByteArrayInputStream(b), Network.TCP);
assertTrue(read.isUDPHostCache());
assertEquals("www.nowhere.org", read.getUDPCacheAddress());
}
public void testPackedIPsInPong() throws Exception {
GGEP ggep = new GGEP();
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(new byte[] { 1, 1, 1, 1, 1, 0 } );
out.write(new byte[] { 1, 2, 3, 4, 2, 0 } );
out.write(new byte[] { 3, 4, 2, 3, 3, 0 } );
out.write(new byte[] { (byte)0xFE, 0, 0, 3, 4, 0 } );
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_IPPORTS, out.toByteArray());
PingReply pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
List l = pr.getPackedIPPorts();
assertEquals(4, l.size());
IpPort ipp = (IpPort)l.get(0);
assertEquals("1.1.1.1", ipp.getAddress());
assertEquals(1, ipp.getPort());
ipp = (IpPort)l.get(1);
assertEquals("1.2.3.4", ipp.getAddress());
assertEquals(2, ipp.getPort());
ipp = (IpPort)l.get(2);
assertEquals("3.4.2.3", ipp.getAddress());
assertEquals(3, ipp.getPort());
ipp = (IpPort)l.get(3);
assertEquals("254.0.0.3", ipp.getAddress());
assertEquals(4, ipp.getPort());
// Try with invalid list of IPs (invalid by not being multiple of 6)
ggep = new GGEP();
out = new ByteArrayOutputStream();
out.write(new byte[] { 1, 1, 1, 1, 1, 0 } );
out.write(new byte[] { 1, 2, 3, 4, 2, 0 } );
out.write(new byte[] { 3, 4, 2, 3, /* no port */ } );
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_IPPORTS, out.toByteArray());
pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
l = pr.getPackedIPPorts();
assertTrue(l.isEmpty());
// Try with invalid IPs (invalid by invalid IP addr)
ggep = new GGEP();
out = new ByteArrayOutputStream();
out.write(new byte[] { 0, 0, 0, 0, 1, 0 } );
out.write(new byte[] { 1, 2, 3, 4, 2, 0 } );
out.write(new byte[] { 3, 4, 2, 3, 3, 0 } );
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_IPPORTS, out.toByteArray());
pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
l = pr.getPackedIPPorts();
assertTrue(l.isEmpty());
// Try with invalid IPs (invalid by invalid port)
ggep = new GGEP();
out = new ByteArrayOutputStream();
out.write(new byte[] { 1, 1, 1, 1, 0, 0 } );
out.write(new byte[] { 1, 2, 3, 4, 2, 0 } );
out.write(new byte[] { 3, 4, 2, 3, 3, 0 } );
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_IPPORTS, out.toByteArray());
pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
l = pr.getPackedIPPorts();
assertTrue(l.isEmpty());
// Make sure the extension works with other GGEP flags (like UDP Host Cache)
ggep = new GGEP();
out = new ByteArrayOutputStream();
out.write(new byte[] { 1, 1, 1, 1, 1, 0 } );
out.write(new byte[] { 1, 2, 3, 4, 2, 0 } );
out.write(new byte[] { 3, 4, 2, 3, 3, 0 } );
out.write(new byte[] { (byte)0xFE, 0, 0, 3, 4, 0 } );
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_IPPORTS, out.toByteArray());
ggep.put(GGEPKeys.GGEP_HEADER_UDP_HOST_CACHE);
pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
assertTrue(pr.isUDPHostCache());
l = pr.getPackedIPPorts();
assertEquals(4, l.size());
ipp = (IpPort)l.get(0);
assertEquals("1.1.1.1", ipp.getAddress());
assertEquals(1, ipp.getPort());
ipp = (IpPort)l.get(1);
assertEquals("1.2.3.4", ipp.getAddress());
assertEquals(2, ipp.getPort());
ipp = (IpPort)l.get(2);
assertEquals("3.4.2.3", ipp.getAddress());
assertEquals(3, ipp.getPort());
ipp = (IpPort)l.get(3);
assertEquals("254.0.0.3", ipp.getAddress());
assertEquals(4, ipp.getPort());
// and make sure we can read from network data.
out = new ByteArrayOutputStream();
pr.write(out);
pr = (PingReply)messageFactory.read(new ByteArrayInputStream(out.toByteArray()), Network.TCP);
assertTrue(pr.isUDPHostCache());
l = pr.getPackedIPPorts();
assertEquals(4, l.size());
ipp = (IpPort)l.get(0);
assertEquals("1.1.1.1", ipp.getAddress());
assertEquals(1, ipp.getPort());
ipp = (IpPort)l.get(1);
assertEquals("1.2.3.4", ipp.getAddress());
assertEquals(2, ipp.getPort());
ipp = (IpPort)l.get(2);
assertEquals("3.4.2.3", ipp.getAddress());
assertEquals(3, ipp.getPort());
ipp = (IpPort)l.get(3);
assertEquals("254.0.0.3", ipp.getAddress());
assertEquals(4, ipp.getPort());
// Try with one of the constructors.
l = new LinkedList(l);
l.add(new Endpoint("1.5.3.5", 5));
pr = pingReplyFactory.create(GUID.makeGuid(), (byte)1, l, null);
assertFalse(pr.isUDPHostCache());
l = pr.getPackedIPPorts();
assertEquals(5, l.size());
ipp = (IpPort)l.get(0);
assertEquals("1.1.1.1", ipp.getAddress());
assertEquals(1, ipp.getPort());
ipp = (IpPort)l.get(1);
assertEquals("1.2.3.4", ipp.getAddress());
assertEquals(2, ipp.getPort());
ipp = (IpPort)l.get(2);
assertEquals("3.4.2.3", ipp.getAddress());
assertEquals(3, ipp.getPort());
ipp = (IpPort)l.get(3);
assertEquals("254.0.0.3", ipp.getAddress());
assertEquals(4, ipp.getPort());
ipp = (IpPort)l.get(4);
assertEquals("1.5.3.5", ipp.getAddress());
assertEquals(5, ipp.getPort());
// Assert none of them supported TLS
for(Object o : l ) {
// right now only TLS-capable hosts become ExtendedEndpoints.
assertNotInstanceof(ExtendedEndpoint.class, o);
}
}
public void testTLSPackedIPPorts() throws Exception {
List l = new LinkedList();
// every % 6 add an endpoint that directly implements HostInfo,
// every % 3 add an endpoint that doesn't, but give HostCatcher a capable
for(int i = 1; i < 11; i++) {
if(i % 6 == 0) {
ExtendedEndpoint ep = new ExtendedEndpoint("1.2.3." + i, i+1);
ep.setTLSCapable(true);
l.add(ep);
assertTrue(hostCatcher.isHostTLSCapable(ep));
} else {
l.add(new IpPortImpl("1.2.3." + i, i+1));
if(i % 3 == 0) {
ExtendedEndpoint ep = new ExtendedEndpoint("1.2.3." + i, i+1);
ep.setTLSCapable(true);
hostCatcher.add(ep, true);
}
assertEquals(i%3==0, hostCatcher.isHostTLSCapable(new IpPortImpl("1.2.3." + i, i+1)));
}
}
PingReply pr = pingReplyFactory.create(GUID.makeGuid(), (byte)1, l, null);
l = pr.getPackedIPPorts();
assertEquals(10, l.size());
for(int i = 1; i < 11; i++) {
IpPort ipp = (IpPort)l.get(i-1);
assertEquals("1.2.3." + i, ipp.getAddress());
assertEquals(i+1, ipp.getPort());
// These are the TLS hosts
if(i%3==0) {
assertInstanceof(ExtendedEndpoint.class, ipp);
assertTrue(((ExtendedEndpoint)ipp).isTLSCapable());
} else {
assertNotInstanceof(ExtendedEndpoint.class, ipp);
}
}
}
public void testNetworkTLSPackedIpPorts() throws Exception {
GGEP ggep = new GGEP();
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(new byte[] { 1, 1, 1, 1, 1, 0 } );
out.write(new byte[] { 1, 2, 3, 4, 2, 0 } );
out.write(new byte[] { 3, 4, 2, 3, 3, 0 } );
out.write(new byte[] { (byte)0xFE, 0, 0, 3, 4, 0 } );
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_IPPORTS, out.toByteArray());
// mark the second & third items as TLS (and the fifth, just to see if it will ignore it)
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_IPPORTS_TLS, (0x40 | 0x20 | 0x8));
PingReply pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
List l = pr.getPackedIPPorts();
assertEquals(4, l.size());
IpPort ipp = (IpPort)l.get(0);
assertEquals("1.1.1.1", ipp.getAddress());
assertEquals(1, ipp.getPort());
assertNotInstanceof(ExtendedEndpoint.class, ipp);
ipp = (IpPort)l.get(1);
assertEquals("1.2.3.4", ipp.getAddress());
assertEquals(2, ipp.getPort());
assertInstanceof(ExtendedEndpoint.class, ipp);
assertTrue(((ExtendedEndpoint)ipp).isTLSCapable());
ipp = (IpPort)l.get(2);
assertEquals("3.4.2.3", ipp.getAddress());
assertEquals(3, ipp.getPort());
assertInstanceof(ExtendedEndpoint.class, ipp);
assertTrue(((ExtendedEndpoint)ipp).isTLSCapable());
ipp = (IpPort)l.get(3);
assertEquals("254.0.0.3", ipp.getAddress());
assertEquals(4, ipp.getPort());
assertNotInstanceof(ExtendedEndpoint.class, ipp);
// and make sure we can read from network data.
out = new ByteArrayOutputStream();
pr.write(out);
pr = (PingReply)messageFactory.read(new ByteArrayInputStream(out.toByteArray()), Network.TCP);
l = pr.getPackedIPPorts();
assertEquals(4, l.size());
ipp = (IpPort)l.get(0);
assertEquals("1.1.1.1", ipp.getAddress());
assertEquals(1, ipp.getPort());
assertNotInstanceof(ExtendedEndpoint.class, ipp);
ipp = (IpPort)l.get(1);
assertEquals("1.2.3.4", ipp.getAddress());
assertEquals(2, ipp.getPort());
assertInstanceof(ExtendedEndpoint.class, ipp);
assertTrue(((ExtendedEndpoint)ipp).isTLSCapable());
ipp = (IpPort)l.get(2);
assertEquals("3.4.2.3", ipp.getAddress());
assertEquals(3, ipp.getPort());
assertInstanceof(ExtendedEndpoint.class, ipp);
assertTrue(((ExtendedEndpoint)ipp).isTLSCapable());
ipp = (IpPort)l.get(3);
assertEquals("254.0.0.3", ipp.getAddress());
assertEquals(4, ipp.getPort());
assertNotInstanceof(ExtendedEndpoint.class, ipp);
}
public void testPackedHostCachesInPong() throws Exception {
// test with compression.
GGEP ggep = new GGEP();
List addrs = new LinkedList();
addrs.add("1.2.3.4:81");
addrs.add("www.limewire.com:6379");
addrs.add("www.eff.org");
addrs.add("www.test.org:1&something=somethingelse¬hing=this");
ggep.putCompressed(GGEPKeys.GGEP_HEADER_PACKED_HOSTCACHES, toBytes(addrs));
PingReply pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
Set s = new TreeSet(IpPort.COMPARATOR);
s.addAll(pr.getPackedUDPHostCaches());
assertEquals(4, s.size());
IpPort ipp = new IpPortImpl("1.2.3.4", 81);
assertContains(s, ipp);
s.remove(ipp);
ipp = new IpPortImpl("www.limewire.com", 6379);
assertContains(s, ipp);
s.remove(ipp);
ipp = new IpPortImpl("www.eff.org", 6346);
assertContains(s, ipp);
s.remove(ipp);
ipp = new IpPortImpl("www.test.org", 1);
assertContains(s, ipp);
s.remove(ipp);
assertEquals(0, s.size());
// test without compression
ggep = new GGEP();
addrs.clear();
addrs.add("1.2.3.4:81");
addrs.add("www.limewire.com:6379");
addrs.add("www.eff.org");
addrs.add("www.test.org:1&something=somethingelse¬hing=this");
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_HOSTCACHES, toBytes(addrs));
pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
s.clear();
s.addAll(pr.getPackedUDPHostCaches());
assertEquals(4, s.size());
ipp = new IpPortImpl("1.2.3.4", 81);
assertContains(s, ipp);
s.remove(ipp);
ipp = new IpPortImpl("www.limewire.com", 6379);
assertContains(s, ipp);
s.remove(ipp);
ipp = new IpPortImpl("www.eff.org", 6346);
assertContains(s, ipp);
s.remove(ipp);
ipp = new IpPortImpl("www.test.org", 1);
assertContains(s, ipp);
s.remove(ipp);
assertEquals(0, s.size());
ggep = new GGEP();
addrs.clear();
addrs.add("1.2.3.4:");
addrs.add("3.4.2.3");
addrs.add("5.4.3.2:1:1");
addrs.add("13.13.1.1:notanumber");
ggep.putCompressed(GGEPKeys.GGEP_HEADER_PACKED_HOSTCACHES, toBytes(addrs));
pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
s.addAll(pr.getPackedUDPHostCaches());
assertEquals(1, s.size());
ipp = new IpPortImpl("3.4.2.3", 6346);
assertContains(s, ipp);
s.remove(ipp);
assertEquals(0, s.size());
ggep = new GGEP();
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_HOSTCACHES, new byte[0]);
pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
assertEquals(0, pr.getPackedUDPHostCaches().size());
ggep = new GGEP();
ggep.putCompressed(GGEPKeys.GGEP_HEADER_PACKED_HOSTCACHES, new byte[] { 1, 1, 1, 1 } );
pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
assertEquals(0, pr.getPackedUDPHostCaches().size());
ggep = new GGEP();
ggep.put(GGEPKeys.GGEP_HEADER_PACKED_HOSTCACHES, new byte[] { 1, 1, 1, 1 } );
pr = pingReplyFactory.create(
GUID.makeGuid(), (byte)1, 1, new byte[] { 1, 1, 1, 1 },
0, 0, false, ggep);
assertEquals(0, pr.getPackedUDPHostCaches().size());
}
private byte[] toBytes(List l) throws Exception {
StringBuffer sb = new StringBuffer();
for(Iterator i = l.iterator(); i.hasNext(); ) {
sb.append(i.next().toString());
if(i.hasNext())
sb.append("\n");
}
return sb.toString().getBytes();
}
private void addIP(byte[] payload) {
// fill up the ip so its not blank.
payload[2] = 1;
payload[3] = 1;
payload[4] = 1;
payload[5] = 1;
}
/**
* Utility class that overrides ConnectionManager methods for getting the
* number of free leaf and ultrapeer slots.
*/
@Singleton
private static class TestConnectionManager extends ConnectionManagerImpl {
private int NUM_FREE_NON_LEAF_SLOTS;
private int NUM_FREE_LEAF_SLOTS;
@Inject
public TestConnectionManager(NetworkManager networkManager,
Provider<HostCatcher> hostCatcher,
@Named("global") Provider<ConnectionDispatcher> connectionDispatcher,
@Named("backgroundExecutor") ScheduledExecutorService backgroundExecutor,
Provider<SimppManager> simppManager,
CapabilitiesVMFactory capabilitiesVMFactory,
RoutedConnectionFactory managedConnectionFactory,
Provider<QueryUnicaster> queryUnicaster,
SocketsManager socketsManager,
ConnectionServices connectionServices,
Provider<NodeAssigner> nodeAssigner,
Provider<IPFilter> ipFilter,
ConnectionCheckerManager connectionCheckerManager,
PingRequestFactory pingRequestFactory,
NetworkInstanceUtils networkInstanceUtils) {
super(networkManager, hostCatcher, connectionDispatcher,
backgroundExecutor, simppManager, capabilitiesVMFactory,
managedConnectionFactory, queryUnicaster,
socketsManager, connectionServices, nodeAssigner,
ipFilter, connectionCheckerManager, pingRequestFactory, networkInstanceUtils);
}
@Override
public int getNumFreeNonLeafSlots() {
return NUM_FREE_NON_LEAF_SLOTS != 0 ? NUM_FREE_NON_LEAF_SLOTS : super.getNumFreeNonLeafSlots();
}
public void setNumFreeNonLeafSlots(int numFreeNonLeafSlots) {
NUM_FREE_NON_LEAF_SLOTS = numFreeNonLeafSlots;
}
@Override
public int getNumFreeLeafSlots() {
return NUM_FREE_LEAF_SLOTS != 0 ? NUM_FREE_LEAF_SLOTS : super.getNumFreeLeafSlots();
}
public void setNumFreeLeafSlots(int numFreeLeafSlots) {
NUM_FREE_LEAF_SLOTS = numFreeLeafSlots;
}
}
// TODO: build a test to test multiple GGEP blocks in the payload!! the
// implementation does not cover this it seems, so it should fail ;)
}