package com.limegroup.gnutella;
import java.io.File;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.util.Iterator;
import junit.framework.Test;
import com.limegroup.gnutella.handshaking.LeafHeaders;
import com.limegroup.gnutella.handshaking.UltrapeerHeaders;
import com.limegroup.gnutella.messages.FeatureSearchData;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.messages.QueryRequest;
import com.limegroup.gnutella.messages.vendor.CapabilitiesVM;
import com.limegroup.gnutella.routing.QueryRouteTable;
import com.limegroup.gnutella.routing.RouteTableMessage;
import com.limegroup.gnutella.settings.ConnectionSettings;
import com.limegroup.gnutella.settings.FilterSettings;
import com.limegroup.gnutella.settings.SharingSettings;
import com.limegroup.gnutella.settings.UltrapeerSettings;
import com.limegroup.gnutella.stubs.ActivityCallbackStub;
import com.limegroup.gnutella.util.BaseTestCase;
import com.limegroup.gnutella.util.CommonUtils;
import com.limegroup.gnutella.util.EmptyResponder;
/**
* Tests that an Ultrapeer correctly handles connect back redirect messages.
*
* ULTRAPEER_1 ---- CENTRAL TEST ULTRAPEER ---- ULTRAPEER_2
* |
* |
* |
* LEAF
*
* This test only covers Ultrapeer behavior - leaves don't participate in
* server side connect back stuff.
*/
public final class ServerSideWhatIsRoutingTest extends BaseTestCase {
/**
* The port that the central Ultrapeer listens on, and that the other nodes
* connect to it on.
*/
private static final int PORT = 6667;
/**
* The timeout value for sockets -- how much time we wait to accept
* individual messages before giving up.
*/
private static final int TIMEOUT = 2000;
/**
* The default TTL to use for request messages.
*/
private final static byte TTL = 7;
/**
* The "soft max" TTL used by LimeWire's message routing -- hops + ttl
* greater than this value have their TTLs automatically reduced
*/
private static final byte SOFT_MAX = 3;
/**
* The TTL of the initial "probe" queries that the Ultrapeer uses to
* determine how widely distributed a file is.
*/
private static final byte PROBE_QUERY_TTL = 2;
/**
* Leaf connection to the Ultrapeer.
*/
private static Connection LEAF;
/**
* Ultrapeer connection.
*/
private static Connection ULTRAPEER_1;
/**
* Ultrapeer 1 UDP connection.
*/
private static DatagramSocket UDP_ACCESS;
/**
* Just a TCP connection to use for testing.
*/
private static ServerSocket TCP_ACCESS;
/**
* The port for TCP_ACCESS
*/
private static final int TCP_ACCESS_PORT = 10776;
/**
* Second Ultrapeer connection
*/
private static Connection ULTRAPEER_2;
/**
* The central Ultrapeer used in the test.
*/
private static final RouterService ROUTER_SERVICE =
new RouterService(new ActivityCallbackStub());
public ServerSideWhatIsRoutingTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(ServerSideWhatIsRoutingTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
private static void buildConnections() throws Exception {
ULTRAPEER_1 = new Connection("localhost", PORT);
UDP_ACCESS = new DatagramSocket();
TCP_ACCESS = new ServerSocket(TCP_ACCESS_PORT);
ULTRAPEER_2 = new Connection("localhost", PORT);
}
public static void setSettings() {
FilterSettings.BLACK_LISTED_IP_ADDRESSES.setValue(
new String[] {"*.*.*.*"});
FilterSettings.WHITE_LISTED_IP_ADDRESSES.setValue(
new String[] {"127.*.*.*"});
ConnectionSettings.PORT.setValue(PORT);
SharingSettings.EXTENSIONS_TO_SHARE.setValue("txt;");
// get the resource file for com/limegroup/gnutella
File berkeley =
CommonUtils.getResourceFile("com/limegroup/gnutella/berkeley.txt");
File susheel =
CommonUtils.getResourceFile("com/limegroup/gnutella/susheel.txt");
// now move them to the share dir
CommonUtils.copy(berkeley, new File(_sharedDir, "berkeley.txt"));
CommonUtils.copy(susheel, new File(_sharedDir, "susheel.txt"));
ConnectionSettings.CONNECT_ON_STARTUP.setValue(false);
UltrapeerSettings.EVER_ULTRAPEER_CAPABLE.setValue(true);
UltrapeerSettings.DISABLE_ULTRAPEER_MODE.setValue(false);
UltrapeerSettings.FORCE_ULTRAPEER_MODE.setValue(true);
UltrapeerSettings.MAX_LEAVES.setValue(4);
ConnectionSettings.NUM_CONNECTIONS.setValue(3);
ConnectionSettings.LOCAL_IS_PRIVATE.setValue(false);
ConnectionSettings.USE_GWEBCACHE.setValue(false);
ConnectionSettings.WATCHDOG_ACTIVE.setValue(false);
}
public static void globalSetUp() throws Exception {
setSettings();
assertEquals("unexpected port", PORT,
ConnectionSettings.PORT.getValue());
ROUTER_SERVICE.start();
ROUTER_SERVICE.clearHostCatcher();
ROUTER_SERVICE.connect();
connect();
assertEquals("unexpected port", PORT,
ConnectionSettings.PORT.getValue());
}
public void setUp() {
setSettings();
}
public static void globalTearDown() throws Exception {
ROUTER_SERVICE.disconnect();
sleep();
if ((LEAF != null) && LEAF.isOpen())
LEAF.close();
ULTRAPEER_1.close();
ULTRAPEER_2.close();
sleep();
UDP_ACCESS.close();
TCP_ACCESS.close();
}
private static void sleep() {
try {Thread.sleep(300);}catch(InterruptedException e) {}
}
/**
* Drains all messages
*/
private static void drainAll() throws Exception {
if(ULTRAPEER_1.isOpen()) {
drain(ULTRAPEER_1);
}
if(ULTRAPEER_2.isOpen()) {
drain(ULTRAPEER_2);
}
if((LEAF != null) && LEAF.isOpen()) {
drain(LEAF);
}
}
/**
* Connects all of the nodes to the central test Ultrapeer.
*/
private static void connect() throws Exception {
buildConnections();
//1. first Ultrapeer connection
ULTRAPEER_2.initialize(new UltrapeerHeaders("localhost"), new EmptyResponder());
//2. second Ultrapeer connection
ULTRAPEER_1.initialize(new UltrapeerHeaders("localhost"), new EmptyResponder());
// for Ultrapeer 1
QueryRouteTable qrt = new QueryRouteTable();
qrt.add("leehsus");
qrt.add("berkeley");
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
ULTRAPEER_1.send((RouteTableMessage)iter.next());
ULTRAPEER_1.flush();
}
assertTrue("ULTRAPEER_2 should be connected", ULTRAPEER_2.isOpen());
assertTrue("ULTRAPEER_1 should be connected", ULTRAPEER_1.isOpen());
LEAF = new Connection("localhost", PORT);
//3. routed leaf, with route table for "test"
LEAF.initialize(new LeafHeaders("localhost"), new EmptyResponder());
qrt = new QueryRouteTable();
qrt.add("berkeley");
qrt.add("susheel");
qrt.addIndivisible(HugeTestUtils.UNIQUE_SHA1.toString());
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
LEAF.send((RouteTableMessage)iter.next());
LEAF.flush();
}
assertTrue("LEAF should be connected", LEAF.isOpen());
// make sure we get rid of any initial ping pong traffic exchanges
sleep();
drainAll();
//sleep();
drainAll();
sleep();
}
// BEGIN TESTS
// ------------------------------------------------------
public void testDoesNotRouteToLeafWhatIsNewQuery() throws Exception {
drainAll();
// send the query
QueryRequest whatIsNewQuery =
new QueryRequest(GUID.makeGuid(), (byte)2,
QueryRequest.WHAT_IS_NEW_QUERY_STRING, "", null,
null, null, false, Message.N_UNKNOWN, false,
FeatureSearchData.WHAT_IS_NEW);
ULTRAPEER_1.send(whatIsNewQuery);
ULTRAPEER_1.flush();
// give time to process
Thread.sleep(1000);
// the Leaf should NOT get this query
QueryRequest rQuery = (QueryRequest) getFirstInstanceOfMessageType(LEAF,
QueryRequest.class);
assertNull(rQuery);
}
public void testDoesRouteToLeafWhatIsNewQuery() throws Exception {
drainAll();
// send the CapabilitiesVM
LEAF.send(CapabilitiesVM.instance());
LEAF.flush();
// send the query
QueryRequest whatIsNewQuery =
new QueryRequest(GUID.makeGuid(), (byte)2,
QueryRequest.WHAT_IS_NEW_QUERY_STRING, "", null,
null, null, false, Message.N_UNKNOWN, false,
FeatureSearchData.WHAT_IS_NEW);
ULTRAPEER_1.send(whatIsNewQuery);
ULTRAPEER_1.flush();
// give time to process
Thread.sleep(1000);
// the Leaf should get this query
QueryRequest rQuery = (QueryRequest) getFirstInstanceOfMessageType(LEAF,
QueryRequest.class);
assertNotNull(rQuery);
assertEquals(new GUID(rQuery.getGUID()),
new GUID(whatIsNewQuery.getGUID()));
// send the LAST HOP query
whatIsNewQuery =
new QueryRequest(GUID.makeGuid(), (byte)1,
QueryRequest.WHAT_IS_NEW_QUERY_STRING, "", null,
null, null, false, Message.N_UNKNOWN, false,
FeatureSearchData.WHAT_IS_NEW);
ULTRAPEER_2.send(whatIsNewQuery);
ULTRAPEER_2.flush();
// give time to process
Thread.sleep(1000);
// the Leaf should get this query
rQuery = (QueryRequest) getFirstInstanceOfMessageType(LEAF,
QueryRequest.class);
assertNotNull(rQuery);
assertEquals(new GUID(rQuery.getGUID()),
new GUID(whatIsNewQuery.getGUID()));
}
public void testDoesNotRouteToUltrapeerWhatIsNewQuery() throws Exception {
drainAll();
// send the query
QueryRequest whatIsNewQuery =
new QueryRequest(GUID.makeGuid(), (byte)2,
QueryRequest.WHAT_IS_NEW_QUERY_STRING, "", null,
null, null, false, Message.N_UNKNOWN, false,
FeatureSearchData.WHAT_IS_NEW);
ULTRAPEER_2.send(whatIsNewQuery);
ULTRAPEER_2.flush();
// give time to process
Thread.sleep(3000);
// the UP should NOT get this query
QueryRequest rQuery =
(QueryRequest) getFirstInstanceOfMessageType(ULTRAPEER_1,
QueryRequest.class);
assertNull(rQuery);
}
public void testDoesRouteToUltrapeerWhatIsNewQuery() throws Exception {
drainAll();
// send the CapabilitiesVM
ULTRAPEER_1.send(CapabilitiesVM.instance());
ULTRAPEER_1.flush();
// send the query
QueryRequest whatIsNewQuery =
new QueryRequest(GUID.makeGuid(), (byte)2,
QueryRequest.WHAT_IS_NEW_QUERY_STRING, "", null,
null, null, false, Message.N_UNKNOWN, false,
FeatureSearchData.WHAT_IS_NEW);
ULTRAPEER_2.send(whatIsNewQuery);
ULTRAPEER_2.flush();
// give time to process
Thread.sleep(1000);
// the UP should get this query
QueryRequest rQuery =
(QueryRequest) getFirstInstanceOfMessageType(ULTRAPEER_1,
QueryRequest.class);
assertNotNull(rQuery);
assertEquals(new GUID(rQuery.getGUID()),
new GUID(whatIsNewQuery.getGUID()));
}
// Ultrapeer 1 should get the query, Ultrapeer 2 should not (because UP 1
// sent the capabilites VM)
public void testLeafQueryRoutesCorrectly() throws Exception {
drainAll();
// send the query
QueryRequest whatIsNewQuery =
new QueryRequest(GUID.makeGuid(), (byte)2,
QueryRequest.WHAT_IS_NEW_QUERY_STRING, "", null,
null, null, false, Message.N_UNKNOWN, false,
FeatureSearchData.WHAT_IS_NEW);
LEAF.send(whatIsNewQuery);
LEAF.flush();
// give time to process
Thread.sleep(5000);
// UP 1 should get this query
QueryRequest rQuery =
(QueryRequest) getFirstInstanceOfMessageType(ULTRAPEER_1,
QueryRequest.class);
assertNotNull(rQuery);
assertEquals(new GUID(rQuery.getGUID()),
new GUID(whatIsNewQuery.getGUID()));
// UP 2 should NOT get this query
rQuery = (QueryRequest) getFirstInstanceOfMessageType(ULTRAPEER_2,
QueryRequest.class);
assertNull(rQuery);
}
public void testUnsupportedQueryForwardedCorrectly() throws Exception {
drainAll();
// send the query
QueryRequest unknownFeatureQuery =
new QueryRequest(GUID.makeGuid(), (byte)3,
QueryRequest.WHAT_IS_NEW_QUERY_STRING, "", null,
null, null, false, Message.N_UNKNOWN, false,
FeatureSearchData.FEATURE_SEARCH_MAX_SELECTOR+1);
ULTRAPEER_2.send(unknownFeatureQuery);
ULTRAPEER_2.flush();
// give time to process
Thread.sleep(4000);
// the Leaf should NOT get this query
QueryRequest rQuery = (QueryRequest) getFirstInstanceOfMessageType(LEAF,
QueryRequest.class);
assertNull(rQuery);
// Ultrapeer 1 should get it though
rQuery =
(QueryRequest) getFirstInstanceOfMessageType(ULTRAPEER_1,
QueryRequest.class);
assertNotNull(rQuery);
assertEquals(new GUID(rQuery.getGUID()),
new GUID(unknownFeatureQuery.getGUID()));
}
public void testLastHopUnsupportedQueryForwardedCorrectly()
throws Exception {
drainAll();
// send the query
QueryRequest unknownFeatureQuery =
new QueryRequest(GUID.makeGuid(), (byte)2,
QueryRequest.WHAT_IS_NEW_QUERY_STRING, "", null,
null, null, false, Message.N_UNKNOWN, false,
FeatureSearchData.FEATURE_SEARCH_MAX_SELECTOR+1);
ULTRAPEER_2.send(unknownFeatureQuery);
ULTRAPEER_2.flush();
// give time to process
Thread.sleep(4000);
// the Leaf should NOT get this query
QueryRequest rQuery = (QueryRequest) getFirstInstanceOfMessageType(LEAF,
QueryRequest.class);
assertNull(rQuery);
// Ultrapeer 1 should get it though
rQuery =
(QueryRequest) getFirstInstanceOfMessageType(ULTRAPEER_1,
QueryRequest.class);
assertNotNull(rQuery);
assertEquals(new GUID(rQuery.getGUID()),
new GUID(unknownFeatureQuery.getGUID()));
}
// ------------------------------------------------------
}