package com.limegroup.gnutella;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import junit.framework.Test;
import com.bitzi.util.Base32;
import com.limegroup.gnutella.handshaking.LeafHeaders;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.messages.PushRequest;
import com.limegroup.gnutella.messages.vendor.MessagesSupportedVendorMessage;
import com.limegroup.gnutella.messages.vendor.PushProxyAcknowledgement;
import com.limegroup.gnutella.messages.vendor.PushProxyRequest;
import com.limegroup.gnutella.routing.QueryRouteTable;
import com.limegroup.gnutella.routing.RouteTableMessage;
import com.limegroup.gnutella.stubs.ActivityCallbackStub;
import com.limegroup.gnutella.util.EmptyResponder;
import com.limegroup.gnutella.util.NetworkUtils;
/**
* Tests that an Ultrapeer correctly handles all aspects of PushProxy. For
* example:
* 1) handles the VendorMessage exchange as expected
* 2) handles HTTP requests as expected, forwarding on a PushRequest
*
* This class tests a lot of different pieces of code.
*
* ULTRAPEER_1 ---- CENTRAL TEST ULTRAPEER ---- ULTRAPEER_2
* |
* |
* |
* LEAF
*
* The leaf must be connected in the first test.
*/
public final class ServerSidePushProxyTest extends ServerSideTestCase {
/**
* The timeout value for sockets -- how much time we wait to accept
* individual messages before giving up.
*/
private static final int TIMEOUT = 2000;
/**
* the client guid of the LEAF - please set in the first test.
*/
private static byte[] clientGUID = null;
/**
* the client GUID of the leaf as a GUID.
*/
private static GUID leafGUID = null;
public ServerSidePushProxyTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(ServerSidePushProxyTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
public static Integer numUPs() {
return new Integer(1);
}
public static Integer numLeaves() {
return new Integer(1);
}
public static ActivityCallback getActivityCallback() {
return new ActivityCallbackStub();
}
public static void setUpQRPTables() throws Exception {
// for Ultrapeer 1
QueryRouteTable qrt = new QueryRouteTable();
qrt.add("leehsus");
qrt.add("berkeley");
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
ULTRAPEER[0].send((RouteTableMessage)iter.next());
ULTRAPEER[0].flush();
}
}
// BEGIN TESTS
// ------------------------------------------------------
// THIS TEST MUST BE FIRST - MAKES SURE THE UP SUPPORTS THE PUSHPROXY VM
// EXCHANGE AND SETS UP OTHER TESTS
public void testEstablishPushProxy() throws Exception {
drainAll();
Message m = null;
clientGUID = GUID.makeGuid();
leafGUID = new GUID(clientGUID);
LEAF[0] = new Connection("localhost", PORT);
// routed leaf, with route table for "test"
LEAF[0].initialize(new LeafHeaders("localhost"), new EmptyResponder());
QueryRouteTable 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[0].send((RouteTableMessage)iter.next());
LEAF[0].flush();
}
// make sure UP is advertised proxy support
do {
m = LEAF[0].receive(TIMEOUT);
} while (!(m instanceof MessagesSupportedVendorMessage)) ;
assertTrue(((MessagesSupportedVendorMessage)m).supportsPushProxy() > 0);
// send proxy request
PushProxyRequest req = new PushProxyRequest(new GUID(clientGUID));
LEAF[0].send(req);
LEAF[0].flush();
// wait for ack
do {
m = LEAF[0].receive(TIMEOUT);
} while (!(m instanceof PushProxyAcknowledgement)) ;
assertTrue(Arrays.equals(m.getGUID(), clientGUID));
assertEquals(PORT, ((PushProxyAcknowledgement)m).getListeningPort());
// ultrapeer supports push proxy setup A-OK
}
public void testGETWithServerId() throws Exception {
tRequest("GET", // request method.
"/gnutella/push-proxy", // the request
"ServerID", // initial param
Base32.encode(clientGUID), // initial value
"127.0.0.1", // ip
6346, // port
null, // params
202); // opcode expected in return
}
public void testHEADWithServerId() throws Exception {
tRequest("HEAD", "/gnutella/push-proxy", "Serverid",
Base32.encode(clientGUID), "10.238.1.87", 6350, null, 202);
}
public void testInvalidGUIDWithServerId() throws Exception {
tRequest("GET", "/gnutella/push-proxy", "serverid",
Base32.encode(GUID.makeGuid()), "127.0.0.1", 6346, null, 410);
}
public void testInvalidGUIDWithGuid() throws Exception {
tRequest("GET", "/gnutella/push-proxy", "guid",
new GUID().toHexString(), "127.0.0.1", 6346, null, 410);
}
public void testInvalidIP() throws Exception {
tRequest("GET", "/gnutella/push-proxy", "serverid",
Base32.encode(clientGUID), "www.crapalapadapa.com",
6346, null, 400);
}
public void testServerIdWithBase16Fails() throws Exception {
tRequest("GET", "/gnutella/push-proxy", "serverid",
leafGUID.toHexString(), "127.0.0.1", 6346, null, 400);
}
public void testGuidIsBase16() throws Exception {
tRequest("GET", "/gnutella/push-proxy", "guid",
leafGUID.toHexString(), "127.0.0.1", 6346, null, 202);
}
public void testGuidWithBase32Fails() throws Exception {
tRequest("GET", "/gnutella/push-proxy", "guid",
Base32.encode(clientGUID), "127.0.0.1", 6346, null, 400);
}
public void testGuidWithGnet() throws Exception {
tRequest("GET", "/gnet/push-proxy", "guid",
Base32.encode(clientGUID), "127.0.0.1", 6346, null, 400);
}
public void testFileChangesIndex() throws Exception {
Map m = new HashMap();
m.put("file", new Integer(34));
tRequest("GET", "/gnutella/push-proxy", "guid",
leafGUID.toHexString(), "127.0.0.1", 6346, m, 202);
}
public void testFileWithGnet() throws Exception {
Map m = new HashMap();
m.put("file", new Integer(34));
tRequest("GET", "/gnet/push-proxy", "guid",
leafGUID.toHexString(), "127.0.0.1", 6346, m, 202);
}
public void testCannotHaveServeridAndGuid() throws Exception {
Map m = new HashMap();
m.put("serverid", Base32.encode(clientGUID));
tRequest("GET", "/gnutella/push-proxy", "guid",
leafGUID.toHexString(), "127.0.0.1", 6346, m, 400);
}
public void testMultipleFileFails() throws Exception {
Map m = new HashMap();
m.put("FILE", new Integer(1));
m.put("file", new Integer(2));
tRequest("GET", "/gnutella/push-proxy", "guid",
leafGUID.toHexString(), "127.0.0.1", 6346, m, 400);
}
public void testFirewallTransferPushProxyWorks() throws Exception {
Map m = new HashMap();
m.put("file", new Integer((int)PushRequest.FW_TRANS_INDEX));
tRequest("GET", "/gnutella/push-proxy", "ServerID",
Base32.encode(clientGUID), "127.0.0.1", 6346, m, 202);
}
private void tRequest(String reqMethod, String reqKey, String initKey,
String guid, String ip, int port, Map params,
int opcode)
throws Exception {
Socket s = new Socket("localhost", PORT);
BufferedReader in =
new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter out =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String result = null;
Message m = null;
out.write(reqMethod + " " + reqKey + "?");
out.write(initKey + "=" + guid);
if( params != null ) {
for(Iterator i = params.entrySet().iterator(); i.hasNext(); ) {
Map.Entry entry = (Map.Entry)i.next();
out.write("&" + entry.getKey() + "=" + entry.getValue());
}
}
out.write(" HTTP/1.1.\r\n");
out.write("X-Node: ");
out.write(ip + ":" + port + "\r\n");
out.write("\r\n");
out.flush();
// check opcode - less important, but might as well
result = in.readLine();
assertGreaterThan(result, -1, result.indexOf("" + opcode));
// clear out other responses
while (in.readLine() != null) ;
if( opcode != 202 ) {
// leaf NOT expecting PushRequest.
try {
do {
m = LEAF[0].receive(TIMEOUT);
assertTrue(!(m instanceof PushRequest));
} while (true) ;
}
catch (InterruptedIOException expected) {}
} else {
// leaf should get PushRequest
do {
m = LEAF[0].receive(TIMEOUT);
} while (!(m instanceof PushRequest)) ;
PushRequest pr = (PushRequest) m;
int idx = 0;
if(params != null && params.get("file") != null )
idx = ((Integer)params.get("file")).intValue();
assertEquals(idx, pr.getIndex());
assertEquals(new GUID(clientGUID), new GUID(pr.getClientGUID()));
assertEquals(port, pr.getPort());
assertEquals(ip, NetworkUtils.ip2string(pr.getIP()));
}
}
}