package com.limegroup.gnutella;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import junit.framework.Test;
import org.limewire.core.settings.ConnectionSettings;
import org.limewire.core.settings.SearchSettings;
import org.limewire.gnutella.tests.LimeTestUtils;
import org.limewire.gnutella.tests.NetworkManagerStub;
import org.limewire.io.GUID;
import org.limewire.security.SecurityToken;
import org.limewire.util.PrivilegedAccessor;
import com.google.inject.Injector;
import com.limegroup.gnutella.connection.BlockingConnection;
import com.limegroup.gnutella.helpers.UrnHelper;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.messages.MessageFactory;
import com.limegroup.gnutella.messages.QueryReply;
import com.limegroup.gnutella.messages.QueryReplyFactory;
import com.limegroup.gnutella.messages.QueryRequest;
import com.limegroup.gnutella.messages.QueryRequestFactory;
import com.limegroup.gnutella.messages.Message.Network;
import com.limegroup.gnutella.messages.vendor.LimeACKVendorMessage;
import com.limegroup.gnutella.messages.vendor.MessagesSupportedVendorMessage;
import com.limegroup.gnutella.messages.vendor.OOBProxyControlVendorMessage;
import com.limegroup.gnutella.messages.vendor.QueryStatusResponse;
import com.limegroup.gnutella.messages.vendor.ReplyNumberVendorMessage;
import com.limegroup.gnutella.messages.vendor.ReplyNumberVendorMessageFactory;
import com.limegroup.gnutella.messages.vendor.OOBProxyControlVendorMessage.Control;
import com.limegroup.gnutella.routing.QueryRouteTable;
import com.limegroup.gnutella.routing.RouteTableMessage;
import com.limegroup.gnutella.search.SearchResultHandler;
/**
* Tests that an Ultrapeer correctly proxies for a Leaf.
*
* ULTRAPEER[0] ---- CENTRAL TEST ULTRAPEER ---- ULTRAPEER[1]
* |
* |
* |
* LEAF[0]
*
*/
@SuppressWarnings( { "cast" } )
public final class ServerSideOOBProxyTest extends ServerSideTestCase {
private final int MAX_RESULTS = SearchResultHandler.MAX_RESULTS;
private final long EXPIRE_TIME = 20 * 1000;
private QueryRequestFactory queryRequestFactory;
private QueryReplyFactory queryReplyFactory;
/**
* Ultrapeer 1 UDP connection.
*/
private static DatagramSocket UDP_ACCESS;
private MessagesSupportedVendorMessage messagesSupportedVendorMessage;
private NetworkManagerStub networkManagerStub;
private ResponseFactory responseFactory;
private ReplyNumberVendorMessageFactory replyNumberVendorMessageFactory;
private MessageFactory messageFactory;
public ServerSideOOBProxyTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(ServerSideOOBProxyTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
@Override
public int getNumberOfUltrapeers() {
return 2;
}
@Override
public int getNumberOfLeafpeers() {
return 2;
}
@Override
public void setSettings() throws Exception {
// we want to test the expirer so make the expire period small
PrivilegedAccessor.setValue(GuidMapManagerImpl.class, "EXPIRE_POLL_TIME", new Long(EXPIRE_TIME));
PrivilegedAccessor.setValue(GuidMapManagerImpl.class, "TIMED_GUID_LIFETIME", new Long(EXPIRE_TIME));
ConnectionSettings.MULTICAST_PORT.setValue(10100);
UDP_ACCESS = new DatagramSocket();
UDP_ACCESS.setSoTimeout(500);
}
@Override
public void setUpQRPTables() throws Exception {
QueryRouteTable qrt = new QueryRouteTable();
qrt.add("stanford");
qrt.add("susheel");
qrt.addIndivisible(UrnHelper.UNIQUE_SHA1.toString());
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
LEAF[0].send((RouteTableMessage)iter.next());
LEAF[0].flush();
}
qrt = new QueryRouteTable();
qrt.add("stanford");
qrt.addIndivisible(UrnHelper.UNIQUE_SHA1.toString());
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
LEAF[1].send((RouteTableMessage)iter.next());
LEAF[1].flush();
}
qrt = new QueryRouteTable();
qrt.add("leehsus");
qrt.add("stanford");
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
ULTRAPEER[0].send((RouteTableMessage)iter.next());
ULTRAPEER[0].flush();
}
qrt = new QueryRouteTable();
qrt.add("leehsus");
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
ULTRAPEER[1].send((RouteTableMessage)iter.next());
ULTRAPEER[1].flush();
}
}
@Override
protected void setUp() throws Exception {
networkManagerStub = new NetworkManagerStub();
Injector injector = LimeTestUtils.createInjector(new LimeTestUtils.NetworkManagerStubModule(networkManagerStub));
super.setUp(injector);
queryRequestFactory = injector.getInstance(QueryRequestFactory.class);
responseFactory = injector.getInstance(ResponseFactory.class);
queryReplyFactory = injector.getInstance(QueryReplyFactory.class);
messagesSupportedVendorMessage = injector.getInstance(MessagesSupportedVendorMessage.class);
replyNumberVendorMessageFactory = injector.getInstance(ReplyNumberVendorMessageFactory.class);
messageFactory = injector.getInstance(MessageFactory.class);
}
private void establishOOBAbility() throws Exception {
networkManagerStub.setCanReceiveSolicited(true);
networkManagerStub.setCanReceiveUnsolicited(true);
networkManagerStub.setOOBCapable(true);
networkManagerStub.setGuessCapable(true);
sendF(LEAF[0], messagesSupportedVendorMessage);
sendF(LEAF[1], messagesSupportedVendorMessage);
Thread.sleep(100);
}
public void testProxiesOnlyWhenSupposedTo() throws Exception {
// before we set up GUESS we should see that the UP does not proxy
//------------------------------
{
drainAll();
sendF(LEAF[1], messagesSupportedVendorMessage);
Thread.sleep(100); // wait for processing of msvm
QueryRequest query = queryRequestFactory.createQuery("stanford");
sendF(LEAF[1], query);
Thread.sleep(1000);
// the Ultrapeer should get it.
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
assertNotNull(queryRec);
assertEquals(new GUID(query.getGUID()), new GUID(queryRec.getGUID()));
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()), MAX_RESULTS);
sendF(LEAF[1], resp);
}
//------------------------------
networkManagerStub.setCanReceiveSolicited(true);
networkManagerStub.setCanReceiveUnsolicited(true);
networkManagerStub.setOOBCapable(true);
networkManagerStub.setGuessCapable(true);
//no one has sent a MessagesSupportedVM yet so no queries should be
//proxied
//------------------------------
{
drainAll();
QueryRequest query = queryRequestFactory.createQuery("stanford");
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it.
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
assertNotNull(queryRec);
assertEquals(new GUID(query.getGUID()), new GUID(queryRec.getGUID()));
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
}
//------------------------------
//now send a MSM and make sure that the query is proxied
//------------------------------
{
drainAll();
sendF(LEAF[0], messagesSupportedVendorMessage);
Thread.sleep(100); // wait for processing of msvm
QueryRequest query = queryRequestFactory.createQuery("stanford");
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it and proxy it
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
assertNotNull(queryRec);
assertTrue(queryRec.desiresOutOfBandReplies());
byte[] proxiedGuid = new byte[queryRec.getGUID().length];
System.arraycopy(queryRec.getGUID(), 0, proxiedGuid, 0,
proxiedGuid.length);
GUID.addressEncodeGuid(proxiedGuid, networkManagerStub.getAddress(),
networkManagerStub.getPort());
assertEquals(new GUID(proxiedGuid), new GUID(queryRec.getGUID()));
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
}
//------------------------------
//now send a OOB query and make sure it isn't proxied
//------------------------------
{
drainAll();
QueryRequest query =
queryRequestFactory.createOutOfBandQuery("leehsus",
LEAF[0].getInetAddress().getAddress(),
LEAF[0].getPort());
assertTrue(query.desiresOutOfBandRepliesV3());
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it.
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[1],
QueryRequest.class);
assertNotNull(queryRec);
assertTrue(queryRec.desiresOutOfBandReplies());
assertEquals(new GUID(query.getGUID()), new GUID(queryRec.getGUID()));
assertEquals(LEAF[0].getPort(), queryRec.getReplyPort());
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
}
//------------------------------
//now send a 'no proxy' query and make sure it isn't proxied
//------------------------------
{
drainAll();
QueryRequest query = queryRequestFactory.createQueryRequest(GUID.makeGuid(), (byte) 3,
"whatever", null, null, null, false, Network.UNKNOWN, false, 0, true,
0);
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it.
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[1],
QueryRequest.class);
assertNotNull(queryRec);
assertTrue(queryRec.doNotProxy());
assertEquals(new GUID(query.getGUID()), new GUID(queryRec.getGUID()));
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
}
//------------------------------
//we should never proxy for a Ultrapeer
//now send a MSM and make sure that the query is proxied
//------------------------------
{
drainAll();
sendF(ULTRAPEER[0], messagesSupportedVendorMessage);
Thread.sleep(100); // wait for processing of msvm
QueryRequest query = queryRequestFactory.createQuery("stanford");
sendF(ULTRAPEER[0], query);
Thread.sleep(1000);
// the Leaf should get the non-OOB query
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(LEAF[0],
QueryRequest.class);
assertNotNull(queryRec);
assertEquals(new GUID(query.getGUID()), new GUID(queryRec.getGUID()));
// no need shut off query
}
//------------------------------
}
/** tests that v2 queries are upgraded to v3. */
public void testProtocolUpgrade() throws Exception {
establishOOBAbility();
SearchSettings.DISABLE_OOB_V2.setBoolean(false);
drainAll();
QueryRequest nonOOB = queryRequestFactory.createQuery("badger");
assertFalse(nonOOB.desiresOutOfBandReplies());
nonOOB.getPayload()[0] |= 0x0004; // pretend it wants oob v2
sendF(LEAF[0], nonOOB);
QueryRequest OOBv2 =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
// upgraded to v3 and proxied
assertTrue(OOBv2.desiresOutOfBandRepliesV2());
assertTrue(OOBv2.desiresOutOfBandRepliesV3());
byte[] proxiedGuid = OOBv2.getGUID().clone();
GUID.addressEncodeGuid(proxiedGuid, networkManagerStub.getAddress(),
networkManagerStub.getPort());
// guid should be address encoded with proxying ultrapeer
assertEquals(proxiedGuid, OOBv2.getGUID());
}
/** tests that v2 queries are upgraded to v3 and v2 is disabled */
public void testProtocolUpgradeDisableV2() throws Exception {
establishOOBAbility();
SearchSettings.DISABLE_OOB_V2.setBoolean(true);
drainAll();
QueryRequest nonOOB = queryRequestFactory.createQuery("badger");
assertFalse(nonOOB.desiresOutOfBandReplies());
nonOOB.getPayload()[0] |= 0x0004; // pretend it wants oob v2
sendF(LEAF[0], nonOOB);
QueryRequest OOBv2 =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
// upgraded to v3 and proxied, v2 disabled
assertFalse(OOBv2.desiresOutOfBandRepliesV2());
assertTrue(OOBv2.desiresOutOfBandRepliesV3());
byte[] proxiedGuid = OOBv2.getGUID().clone();
GUID.addressEncodeGuid(proxiedGuid, networkManagerStub.getAddress(),
networkManagerStub.getPort());
// guid should be address encoded with proxying ultrapeer
assertEquals(proxiedGuid, OOBv2.getGUID());
}
public void testOOBProxyControlMessage() throws Exception {
establishOOBAbility();
// default case proxying works
{
drainAll();
QueryRequest query = queryRequestFactory.createQuery("stanford");
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it.
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
assertNotNull(queryRec);
byte[] proxiedGuid = query.getGUID().clone();
GUID.addressEncodeGuid(proxiedGuid, networkManagerStub.getAddress(),
networkManagerStub.getPort());
// guid should be address encoded with proxying ultrapeer
assertEquals(proxiedGuid, queryRec.getGUID());
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
}
// turn proxying off for all versions by sending control message
{
drainAll();
OOBProxyControlVendorMessage control = OOBProxyControlVendorMessage.createDoNotProxyMessage();
sendF(LEAF[0], control);
// we have to sleep here, otherwise query is handled before control message
// which is odd since we're sending on the Connection class which does not
// queue messages by priority
Thread.sleep(1000);
QueryRequest query = queryRequestFactory.createQuery("stanford");
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it.
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
assertNotNull(queryRec);
// GUID should be the same and not address encoded by the proxying ultrapeer
assertEquals(query.getGUID(), queryRec.getGUID());
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
}
// turn proxying off for version 2 => proxying should work, since current version is 3
{
drainAll();
OOBProxyControlVendorMessage control = new OOBProxyControlVendorMessage(Control.DISABLE_VERSION_2);
sendF(LEAF[0], control);
Thread.sleep(1000);
QueryRequest query = queryRequestFactory.createQuery("stanford");
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it.
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
assertNotNull(queryRec);
byte[] proxiedGuid = query.getGUID().clone();
GUID.addressEncodeGuid(proxiedGuid, networkManagerStub.getAddress(),
networkManagerStub.getPort());
// guid should be address encoded with proxying ultrapeer
assertEquals(proxiedGuid, queryRec.getGUID());
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
}
// turn proxying off for version 3 => proxying should not work since we are at version 3
{
drainAll();
OOBProxyControlVendorMessage control = new OOBProxyControlVendorMessage(Control.DISABLE_VERSION_3);
sendF(LEAF[0], control);
Thread.sleep(1000);
QueryRequest query = queryRequestFactory.createQuery("stanford");
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it.
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
assertNotNull(queryRec);
// GUID should be the same and not address encoded by the proxying ultrapeer
assertEquals(query.getGUID(), queryRec.getGUID());
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
}
// turn proxying on again
{
drainAll();
OOBProxyControlVendorMessage control = OOBProxyControlVendorMessage.createDoProxyMessage();
sendF(LEAF[0], control);
Thread.sleep(1000);
QueryRequest query = queryRequestFactory.createQuery("stanford");
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it.
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
assertNotNull(queryRec);
byte[] proxiedGuid = query.getGUID().clone();
GUID.addressEncodeGuid(proxiedGuid, networkManagerStub.getAddress(),
networkManagerStub.getPort());
// guid should be address encoded with proxying ultrapeer
assertEquals(proxiedGuid, queryRec.getGUID());
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
}
}
// tests that:
// 1) routed TCP results are mapped
// 2) OOB results are acked and mapped
public void testBasicProxy() throws Exception {
establishOOBAbility();
drainAll();
QueryRequest query = queryRequestFactory.createQuery("stanford");
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it and proxy it
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0],
QueryRequest.class);
assertNotNull(queryRec);
assertTrue(queryRec.desiresOutOfBandReplies());
byte[] proxiedGuid = new byte[queryRec.getGUID().length];
System.arraycopy(queryRec.getGUID(), 0, proxiedGuid, 0,
proxiedGuid.length);
GUID.addressEncodeGuid(proxiedGuid, networkManagerStub.getAddress(),
networkManagerStub.getPort());
assertEquals(new GUID(proxiedGuid), new GUID(queryRec.getGUID()));
// 1) route some TCP results back and make sure they are mapped back to
// the leaf
{
Response[] res = new Response[1];
for (int j = 0; j < res.length; j++)
res[j] = responseFactory.createResponse(10, 10, "stanford0", UrnHelper.SHA1);
Message m =
queryReplyFactory.createQueryReply(proxiedGuid, (byte) 3, 6355,
myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false,
true, true, false, false, null);
sendF(ULTRAPEER[0], m);
Thread.sleep(1000); // processing wait
// leaf should get a reply with the correct guid
QueryReply queryRep =
(QueryReply) BlockingConnectionUtils.getFirstInstanceOfMessageType(LEAF[0],
QueryReply.class);
assertNotNull(queryRep);
assertEquals(new GUID(query.getGUID()),new GUID(queryRep.getGUID()));
assertEquals(((Response)queryRep.getResults().next()).getName(),
"stanford0");
assertEquals(2, queryRep.getTTL());
assertEquals(1, queryRep.getHops());
}
// 2) participate in a OOB exchange and make sure results are mapped
// back to the leaf
{
Response[] res = new Response[1];
for (int j = 0; j < res.length; j++)
res[j] = responseFactory.createResponse(10, 10, "stanford1", UrnHelper.SHA1);
SecurityToken token = exchangeRNVMACK(proxiedGuid);
assertNotNull(token);
Message m =
queryReplyFactory.createQueryReply(proxiedGuid, (byte) 3, 6356,
myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false,
true, true, false, false, null, token);
// send off the reply
ByteArrayOutputStream baos = new ByteArrayOutputStream();
m.write(baos);
DatagramPacket pack = new DatagramPacket(baos.toByteArray(),
baos.toByteArray().length,
InetAddress.getLocalHost(),
PORT);
UDP_ACCESS.send(pack);
// now we should get a reply at the leaf
QueryReply queryRep =
(QueryReply) BlockingConnectionUtils.getFirstInstanceOfMessageType(LEAF[0],
QueryReply.class);
assertNotNull(queryRep);
assertEquals(new GUID(query.getGUID()),new GUID(queryRep.getGUID()));
assertEquals(((Response)queryRep.getResults().next()).getName(),
"stanford1");
assertEquals(2, queryRep.getTTL());
assertEquals(1, queryRep.getHops());
assertEquals(token.getBytes(), queryRep.getSecurityToken());
}
// 3) shut off the query, make sure the OOB is bypassed but TCP is still
// sent
{
// shut off query
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(queryRec.getGUID()),
MAX_RESULTS);
sendF(LEAF[0], resp);
Thread.sleep(500); // let it process
Response[] res = new Response[1];
for (int j = 0; j < res.length; j++)
res[j] = responseFactory.createResponse(10, 10, "stanford2", UrnHelper.SHA1);
Message m =
queryReplyFactory.createQueryReply(proxiedGuid, (byte) 3, 6356,
myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false,
true, true, false, false, null);
// send a ReplyNumberVM
ReplyNumberVendorMessage replyNum =
replyNumberVendorMessageFactory.create(new GUID(proxiedGuid), 1);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
replyNum.write(baos);
DatagramPacket pack = new DatagramPacket(baos.toByteArray(),
baos.toByteArray().length,
InetAddress.getLocalHost(),
PORT);
UDP_ACCESS.send(pack);
// we better not get an ACK
try {
while (true) {
pack = new DatagramPacket(new byte[1000], 1000);
UDP_ACCESS.receive(pack);
InputStream in = new ByteArrayInputStream(pack.getData());
Message mTemp = messageFactory.read(in, Network.TCP);
if (mTemp instanceof LimeACKVendorMessage)
fail("Should not get ACK!!!");
}
}
catch (InterruptedIOException expected) {}
// send via TCP, we better get it...
sendF(ULTRAPEER[0], m);
Thread.sleep(1000); // processing wait
// leaf should get a reply with the correct guid
QueryReply queryRep =
(QueryReply) BlockingConnectionUtils.getFirstInstanceOfMessageType(LEAF[0],
QueryReply.class);
assertNotNull(queryRep);
assertEquals(new GUID(query.getGUID()),new GUID(queryRep.getGUID()));
assertEquals(((Response)queryRep.getResults().next()).getName(),
"stanford2");
assertEquals(2, queryRep.getTTL());
assertEquals(1, queryRep.getHops());
}
}
/**
* Tests that results arriving through OOB for non-proxied queries
* are dropped
*/
public void testDropUnsolicited() throws Exception {
establishOOBAbility();
drainAll();
QueryRequest query = queryRequestFactory.createQueryRequest(GUID.makeGuid(), (byte) 3,
"not proxied", null, null, null, false, Network.UNKNOWN, false, 0, true,
0);
sendF(LEAF[0], query);
Thread.sleep(1000);
// the Ultrapeer should get it and not modify the guid
QueryRequest queryRec =
(QueryRequest) BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[1],
QueryRequest.class);
assertNotNull(queryRec);
assertTrue(queryRec.doNotProxy());
assertEquals(new GUID(query.getGUID()), new GUID(queryRec.getGUID()));
// go through the RNVM and ACK
// (make sure this test breaks should we decide to intercept
// unwelcome responses earlier in the protocol)
SecurityToken token = exchangeRNVMACK(query.getGUID());
// create a bunch of responses for that guid
Response[] res = new Response[1];
for (int j = 0; j < res.length; j++)
res[j] = responseFactory.createResponse(10, 10, "not proxied", UrnHelper.SHA1);
Message m =
queryReplyFactory.createQueryReply(query.getGUID(), (byte) 3, 6356,
myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false,
true, true, false, false, null, token);
// and send them OOB
ByteArrayOutputStream baos = new ByteArrayOutputStream();
m.write(baos);
DatagramPacket pack = new DatagramPacket(baos.toByteArray(),
baos.toByteArray().length,
InetAddress.getLocalHost(),
PORT);
UDP_ACCESS.send(pack);
Thread.sleep(1000);
try {
LEAF[0].receive(1000);
fail("nothing should have arrived");
} catch (IOException expected){}
}
private SecurityToken exchangeRNVMACK(byte[] guid) throws Exception {
// send a ReplyNumberVM
ReplyNumberVendorMessage replyNum =
replyNumberVendorMessageFactory.create(new GUID(guid), 1);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
replyNum.write(baos);
DatagramPacket pack = new DatagramPacket(baos.toByteArray(),
baos.toByteArray().length,
InetAddress.getLocalHost(),
PORT);
UDP_ACCESS.send(pack);
// we expect an ACK
LimeACKVendorMessage ack = null;
while (ack == null) {
pack = new DatagramPacket(new byte[1000], 1000);
try {
UDP_ACCESS.receive(pack);
}
catch (IOException bad) {
fail("Did not get ack", bad);
}
InputStream in = new ByteArrayInputStream(pack.getData());
Message mTemp = messageFactory.read(in, Network.TCP);
if (mTemp instanceof LimeACKVendorMessage)
ack = (LimeACKVendorMessage) mTemp;
}
assertEquals(new GUID(guid), new GUID(ack.getGUID()));
assertEquals(1, ack.getNumResults());
return ack.getSecurityToken();
}
// tests that the expirer works
// this test needs to be more black-boxyish but its hard
public void testExpirer() throws Exception {
establishOOBAbility();
GuidMapManager gmm = injector.getInstance(GuidMapManager.class);
List expireList = (List) PrivilegedAccessor.getValue(gmm,
"toExpire");
// nothing to expire at first
assertTrue(expireList.isEmpty());
{
QueryRequest query = queryRequestFactory.createQuery("sumeet");
sendF(LEAF[0], query);
Thread.sleep(500);
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(query.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
Thread.sleep(500);
}
{
QueryRequest query = queryRequestFactory.createQuery("berlin");
sendF(LEAF[0], query);
Thread.sleep(500);
QueryStatusResponse resp =
new QueryStatusResponse(new GUID(query.getGUID()), MAX_RESULTS);
sendF(LEAF[0], resp);
Thread.sleep(500);
}
Thread.sleep(EXPIRE_TIME*2);
synchronized (gmm) {
assertFalse(expireList.isEmpty());
// iterator through all the maps and confirm they are empty
for(Iterator i = expireList.iterator(); i.hasNext(); ) {
Object guidMapImpl = i.next();
synchronized(guidMapImpl) {
Map currMap = (Map)PrivilegedAccessor.invokeMethod(guidMapImpl, "getMap", (Object[])null);
assertTrue(currMap.isEmpty());
}
}
}
// close the leaf and make sure the MC purges it's guidmap
LEAF[0].close();
Thread.sleep(2000);
assertTrue(expireList.toString(), expireList.isEmpty());
}
private final void sendF(BlockingConnection c, Message m) throws Exception {
c.send(m);
c.flush();
}
private static byte[] myIP() {
return new byte[] { (byte)127, (byte)0, 0, 1 };
}
}