package com.limegroup.gnutella.messages;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.LinkedList;
import java.util.List;
import junit.framework.Test;
import org.limewire.core.settings.ApplicationSettings;
import org.limewire.core.settings.ConnectionSettings;
import org.limewire.core.settings.UltrapeerSettings;
import org.limewire.io.GGEP;
import org.limewire.io.GUID;
import org.limewire.io.LocalSocketAddressProvider;
import org.limewire.net.TLSManager;
import org.limewire.util.NameValue;
import org.limewire.util.PrivilegedAccessor;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.limegroup.gnutella.ConnectionServices;
import com.limegroup.gnutella.LimeTestUtils;
import com.limegroup.gnutella.messages.Message.Network;
import com.limegroup.gnutella.stubs.LocalSocketAddressProviderStub;
@SuppressWarnings("unchecked")
// TODO stub / mock out ping requests
public class PingRequestTest extends com.limegroup.gnutella.util.LimeTestCase {
private PingRequestFactory pingRequestFactory;
private MessageFactory messageFactory;
private ConnectionServices connectionServices;
private TLSManager tlsManager;
public PingRequestTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(PingRequestTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
//TODO: test other parts of ping!
@Override
protected void setUp() throws Exception {
Injector injector = LimeTestUtils.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(LocalSocketAddressProvider.class).to(LocalSocketAddressProviderStub.class);
}
});
pingRequestFactory = injector.getInstance(PingRequestFactory.class);
messageFactory = injector.getInstance(MessageFactory.class);
connectionServices = injector.getInstance(ConnectionServices.class);
tlsManager = injector.getInstance(TLSManager.class);
}
public void testQueryKeyPing() throws Exception {
PingRequest pr = pingRequestFactory.createQueryKeyRequest();
assertFalse(pr.isQueryKeyRequest()); // hasn't been hopped yet
ByteArrayOutputStream baos = new ByteArrayOutputStream();
pr.write(baos);
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
PingRequest prRead = (PingRequest) messageFactory.read(bais, Network.TCP);
prRead.hop();
assertTrue(prRead.isQueryKeyRequest());
}
public void testGGEPPing() throws Exception {
// first make a GGEP block....
GGEP ggepBlock = new GGEP(true);
ggepBlock.put(GGEPKeys.GGEP_HEADER_QUERY_KEY_SUPPORT);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ggepBlock.write(baos);
byte[] ggepBytes = baos.toByteArray();
//Headers plus payload(6 bytes)
byte[] buffer = new byte[23+ggepBytes.length+1];
byte[] guid = GUID.makeGuid();//get a GUID
System.arraycopy(guid,0,buffer,0,guid.length);//copy GUID
int currByte = guid.length;
buffer[currByte] = Message.F_PING;
currByte++;
buffer[currByte] = 0x0001; // TTL
currByte++;
buffer[currByte] = 0x0000;// Hops
currByte++;
buffer[currByte] = (byte)(ggepBytes.length+1);//1st byte = 6
currByte++;
buffer[currByte] = 0x0000;//2nd byte = 0
currByte++;
buffer[currByte] = 0x0000;//3rd byte = 0
currByte++;
buffer[currByte] = 0x0000;//4th byte = 0 - remember it's little endian
currByte++;
// stick in GGEP
for (int i = 0; i < ggepBytes.length; i++)
buffer[currByte++] = ggepBytes[i];
buffer[currByte++] = 0; // trailing 0
assertGreaterThanOrEquals(buffer.length, currByte);
//OK, ggep ping ready
ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
Message m;
m = messageFactory.read(stream, Network.TCP);
PingRequest pr;
pr = (PingRequest)m;
assertTrue(!pr.isQueryKeyRequest());
pr.hop();
assertTrue(pr.isQueryKeyRequest());
//Came this far means its all OK
}
public void testBigPing() throws Exception {
byte[] buffer = new byte[23+16];//Headers plus payload(16 bytes)
//Note: We choose a size of 16 to make sure it does not create a
//group ping,
byte[] guid = GUID.makeGuid();//get a GUID
System.arraycopy(guid,0,buffer,0,guid.length);//copy GUID
int currByte = guid.length;
buffer[currByte] = Message.F_PING;
currByte++;
buffer[currByte] = 0x0004; // TTL
currByte++;
buffer[currByte] = 0x0000;// Hops
currByte++;
buffer[currByte] = 0x0010;//1st byte = 16, A thro' P
currByte++;
buffer[currByte] = 0x0000;//2nd byte = 0
currByte++;
buffer[currByte] = 0x0000;//3rd byte = 0
currByte++;
buffer[currByte] = 0x0000;//4th byte = 0 - remember it's little endian
currByte++;
byte c = 65;//"A"
byte[] payload = new byte[16];//to be used to test constrcutor
for(int i=0; i<16; i++){
buffer[currByte] = c;
payload[i] = buffer[currByte];
currByte++;
c++;
}
//OK, Big ping ready
ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
Message m;
m = messageFactory.read(stream, Network.TCP);
PingRequest pr;
pr = (PingRequest)m;
ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
pr.write(outBuffer);
byte [] outb = outBuffer.toByteArray();
String out = new String(outb,23,outb.length-23);
assertEquals("Wrong payload", "ABCDEFGHIJKLMNOP", out);
//Test the new constructor for big pings read from the network
PingRequest bigPing = pingRequestFactory.createFromNetwork(GUID.makeGuid(), (byte)7,
(byte)0, payload, Network.UNKNOWN);
assertEquals(0, bigPing.getHops());
assertEquals(7, bigPing.getTTL());
assertEquals("bad length", 16, bigPing.getLength());
//Came this far means its all OK
}
public void testAddIP() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//try a ping which doesn't ask for ip
PingRequest noRequest = pingRequestFactory.createPingRequest((byte)1);
assertFalse(noRequest.requestsIP());
noRequest.write(baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
PingRequest fromNet = (PingRequest) messageFactory.read(bais, Network.TCP);
assertFalse(fromNet.requestsIP());
//try a ping without any other ggeps except the ip request
byte []guid = GUID.makeGuid();
PingRequest noPayload = pingRequestFactory.createPingRequest(guid, (byte)1,
(byte)0);
assertFalse(noPayload.requestsIP());
noPayload.addIPRequest();
assertTrue(noPayload.requestsIP());
baos = new ByteArrayOutputStream();
noPayload.write(baos);
bais = new ByteArrayInputStream(baos.toByteArray());
fromNet = (PingRequest) messageFactory.read(bais, Network.TCP);
assertTrue(fromNet.requestsIP());
// now try a ping with locale
String original = ApplicationSettings.LANGUAGE.getValue();
ApplicationSettings.LANGUAGE.setValue("zz");
PingRequest withLocale = pingRequestFactory.createPingRequest((byte)1);
ApplicationSettings.LANGUAGE.setValue(original);
withLocale.addIPRequest();
baos = new ByteArrayOutputStream();
withLocale.write(baos);
bais = new ByteArrayInputStream(baos.toByteArray());
fromNet = (PingRequest) messageFactory.read(bais, Network.TCP);
assertTrue(fromNet.requestsIP());
assertEquals("zz",fromNet.getLocale());
assertFalse(fromNet.supportsCachedPongs());
assertNull(fromNet.getSupportsCachedPongData());
}
public void testUDPPingRequest() {
PingRequest pr = pingRequestFactory.createUDPPing();
assertTrue(pr.supportsCachedPongs());
// Test +UP +TLS
UltrapeerSettings.MIN_CONNECT_TIME.setValue(0);
UltrapeerSettings.FORCE_ULTRAPEER_MODE.setValue(true);
ConnectionSettings.EVER_ACCEPTED_INCOMING.setValue(true);
ConnectionSettings.LOCAL_IS_PRIVATE.setValue(false);
UltrapeerSettings.EVER_ULTRAPEER_CAPABLE.setValue(true);
UltrapeerSettings.NEED_MIN_CONNECT_TIME.setValue(false);
tlsManager.setIncomingTLSEnabled(true);
assertTrue(connectionServices.isSupernode());
pr = pingRequestFactory.createUDPPing();
assertFalse(pr.requestsIP());
byte[] data = pr.getSupportsCachedPongData();
assertEquals(0x1, data[0] & 0x1);
assertEquals(0x2, data[0] & 0x2);
// +UP -TLS
tlsManager.setIncomingTLSEnabled(false);
assertTrue(connectionServices.isSupernode());
pr = pingRequestFactory.createUDPPing();
assertFalse(pr.requestsIP());
data = pr.getSupportsCachedPongData();
assertEquals(0x1, data[0] & 0x1);
assertEquals(0x0, data[0] & 0x2);
// Test -UP +TLS
UltrapeerSettings.DISABLE_ULTRAPEER_MODE.setValue(true);
UltrapeerSettings.FORCE_ULTRAPEER_MODE.setValue(false);
tlsManager.setIncomingTLSEnabled(true);
assertFalse(connectionServices.isSupernode());
pr = pingRequestFactory.createUDPPing();
assertFalse(pr.requestsIP());
data = pr.getSupportsCachedPongData();
assertEquals(0x0, data[0] & 0x1);
assertEquals(0x2, data[0] & 0x2);
// Test -UP -TLS
tlsManager.setIncomingTLSEnabled(false);
assertFalse(connectionServices.isSupernode());
pr = pingRequestFactory.createUDPPing();
assertFalse(pr.requestsIP());
data = pr.getSupportsCachedPongData();
assertEquals(0x0, data[0] & 0x1);
assertEquals(0x0, data[0] & 0x2);
ConnectionSettings.EVER_ACCEPTED_INCOMING.setValue(false);
pr = pingRequestFactory.createUDPPing();
assertTrue(pr.requestsIP());
}
public void testSupportsCachedPongData() throws Exception {
List ggeps = new LinkedList();
ggeps.add(new NameValue(GGEPKeys.GGEP_HEADER_SUPPORT_CACHE_PONGS));
PingRequest pr = make(ggeps);
assertTrue(pr.supportsCachedPongs());
byte[] data = pr.getSupportsCachedPongData();
assertNotNull(data);
assertEquals(0, data.length);
ggeps.clear();
ggeps.add(new NameValue(GGEPKeys.GGEP_HEADER_SUPPORT_CACHE_PONGS, new byte[1]));
pr = make(ggeps);
assertTrue(pr.supportsCachedPongs());
data = pr.getSupportsCachedPongData();
assertNotNull(data);
assertEquals(1, data.length);
}
public void testRequestsDHTIPP() throws Exception{
List ggeps = new LinkedList();
ggeps.add(new NameValue(GGEPKeys.GGEP_HEADER_DHT_IPPORTS));
PingRequest pr = make(ggeps);
assertTrue(pr.requestsDHTIPP());
assertFalse(pr.supportsCachedPongs());
}
private PingRequest make(List ggeps) throws Exception {
return (PingRequest)PrivilegedAccessor.invokeConstructor(
PingRequestImpl.class,
new Object[] { new byte[16], (byte) 1, ggeps },
new Class[] { byte[].class, byte.class, List.class });
}
}