package com.limegroup.gnutella;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.InetAddress;
import java.util.Properties;
import com.limegroup.gnutella.handshaking.HandshakeResponder;
import com.limegroup.gnutella.handshaking.HandshakeResponse;
import com.limegroup.gnutella.handshaking.HeaderNames;
import com.limegroup.gnutella.handshaking.NoGnutellaOkException;
import com.limegroup.gnutella.handshaking.UltrapeerHeaders;
import com.limegroup.gnutella.messages.BadPacketException;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.messages.PingReply;
import com.limegroup.gnutella.messages.PingRequest;
import com.limegroup.gnutella.messages.QueryReply;
import com.limegroup.gnutella.settings.ConnectionSettings;
import com.limegroup.gnutella.settings.SearchSettings;
import com.limegroup.gnutella.settings.SharingSettings;
import com.limegroup.gnutella.settings.UltrapeerSettings;
import com.limegroup.gnutella.settings.FilterSettings;
import com.limegroup.gnutella.spam.SpamManager;
import com.limegroup.gnutella.util.CommonUtils;
import com.limegroup.gnutella.util.PrivilegedAccessor;
/**
* Sets up a Test Scenario of a Leaf connected to some Ultrapeers (default of
* 4, use alternate constructor to specify up to 4)
* The leaf has the following settings (which you can override by implementing
* your own doSettings()): runs on SERVER_PORT, is a Leaf, does not connect on
* startup, GWebCaches and Watchdog are inactive, sharing only txt files,
* sharing two txt files (berkeley and susheel), and accepting all search
* results.
* You must also implement getActivityCallback() (for custom callbacks)
* and numUPs (for the number of Ultrapeers to connect to, must be 1-4),
* and main and suite().
*/
public abstract class ClientSideTestCase
extends com.limegroup.gnutella.util.BaseTestCase {
public static final int SERVER_PORT = 6669;
protected static int TIMEOUT=500;
private static final byte[] ultrapeerIP=
new byte[] {(byte)18, (byte)239, (byte)0, (byte)144};
private static final byte[] oldIP=
new byte[] {(byte)111, (byte)22, (byte)33, (byte)44};
protected static Connection testUP[];
protected static RouterService rs;
private static ActivityCallback callback;
protected static ActivityCallback getCallback() {
return callback;
}
public ClientSideTestCase(String name) {
super(name);
}
private static void doSettings() throws Exception {
String localIP = InetAddress.getLocalHost().getHostAddress();
FilterSettings.BLACK_LISTED_IP_ADDRESSES.setValue(
new String[] {"*.*.*.*"});
FilterSettings.WHITE_LISTED_IP_ADDRESSES.setValue(
new String[] {"127.*.*.*", "192.168.*.*", "10.254.*.*", localIP});
//Setup LimeWire backend. For testing other vendors, you can skip all
//this and manually configure a client in leaf mode to listen on port
//6669, with no slots and no connections. But you need to re-enable
//the interactive prompts below.
ConnectionSettings.PORT.setValue(SERVER_PORT);
ConnectionSettings.CONNECT_ON_STARTUP.setValue(false);
UltrapeerSettings.EVER_ULTRAPEER_CAPABLE.setValue(false);
UltrapeerSettings.DISABLE_ULTRAPEER_MODE.setValue(true);
UltrapeerSettings.FORCE_ULTRAPEER_MODE.setValue(false);
ConnectionSettings.NUM_CONNECTIONS.setValue(0);
ConnectionSettings.LOCAL_IS_PRIVATE.setValue(false);
SharingSettings.EXTENSIONS_TO_SHARE.setValue("txt;");
ConnectionSettings.USE_GWEBCACHE.setValue(false);
ConnectionSettings.WATCHDOG_ACTIVE.setValue(false);
// 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"));
// make sure results get through
SearchSettings.MINIMUM_SEARCH_QUALITY.setValue(-2);
}
public static void globalSetUp(Class callingClass) throws Exception {
// calls all doSettings() for me and my children
PrivilegedAccessor.invokeAllStaticMethods(callingClass, "doSettings",
null);
callback=
(ActivityCallback)PrivilegedAccessor.invokeMethod(callingClass,
"getActivityCallback",
null);
rs=new RouterService(callback);
rs.preGuiInit();
assertEquals("unexpected port",
SERVER_PORT, ConnectionSettings.PORT.getValue());
rs.start();
RouterService.clearHostCatcher();
RouterService.connect();
Thread.sleep(2000);
assertEquals("unexpected port",
SERVER_PORT, ConnectionSettings.PORT.getValue());
connect();
Integer numUPs = (Integer)PrivilegedAccessor.invokeMethod(callingClass,
"numUPs", null);
if ((numUPs.intValue() < 1) || (numUPs.intValue() > 4))
throw new IllegalArgumentException("Bad value for numUPs!!!");
testUP = new Connection[numUPs.intValue()];
for (int i = 0; i < testUP.length; i++) {
try {
testUP[i] = connect(6355+i, true, callingClass);
} catch(NoGnutellaOkException ngoke) {
fail("couldn't connect ultrapeer: " + (i+1) +
", preferred is: " +
RouterService.getConnectionManager().getPreferredConnectionCount(),
ngoke);
}
}
}
public void setUp() throws Exception {
// calls all doSettings() for me and my parents
PrivilegedAccessor.invokeAllStaticMethods(this.getClass(), "doSettings",
null);
}
public static void globalTearDown() throws Exception {
shutdown();
}
////////////////////////// Initialization ////////////////////////
private static void connect()
throws IOException, BadPacketException {
debug("-Establish connections");
}
private static Connection connect(int port,
boolean ultrapeer,
Class callingClass)
throws IOException, BadPacketException, Exception {
ServerSocket ss=new ServerSocket(port);
RouterService.connectToHostAsynchronously("127.0.0.1", port);
Socket socket = ss.accept();
ss.close();
socket.setSoTimeout(3000);
InputStream in=socket.getInputStream();
String word=readWord(in);
if (! word.equals("GNUTELLA"))
throw new IOException("Bad word: "+word);
HandshakeResponder responder;
if (ultrapeer) {
responder = new UltrapeerResponder();
} else {
responder = new OldResponder();
}
Connection con = new Connection(socket);
con.initialize(null, responder);
Boolean shouldReply = Boolean.TRUE;
try {
shouldReply = (Boolean)PrivilegedAccessor.invokeMethod(callingClass,
"shouldRespondToPing", null);
} catch(NoSuchMethodException ignored) {}
if(shouldReply.booleanValue())
replyToPing(con, ultrapeer);
return con;
}
/**
* Acceptor.readWord
*
* @modifies sock
* @effects Returns the first word (i.e., no whitespace) of less
* than 8 characters read from sock, or throws IOException if none
* found.
*/
private static String readWord(InputStream sock) throws IOException {
final int N=9; //number of characters to look at
char[] buf=new char[N];
for (int i=0 ; i<N ; i++) {
int got=sock.read();
if (got==-1) //EOF
throw new IOException();
if ((char)got==' ') { //got word. Exclude space.
return new String(buf,0,i);
}
buf[i]=(char)got;
}
throw new IOException();
}
/**
* Note that this function will _EAT_ messages until it finds a ping to respond to.
*/
private static void replyToPing(Connection c, boolean ultrapeer)
throws Exception {
// respond to a ping iff one is given.
Message m = null;
byte[] guid;
try {
while (!(m instanceof PingRequest)) {
m = c.receive(500);
}
guid = ((PingRequest)m).getGUID();
} catch(InterruptedIOException iioe) {
//nothing's coming, send a fake pong anyway.
guid = new GUID().bytes();
}
Socket socket = (Socket)PrivilegedAccessor.getValue(c, "_socket");
PingReply reply =
PingReply.createExternal(guid, (byte)7,
socket.getLocalPort(),
ultrapeer ? ultrapeerIP : oldIP,
ultrapeer);
reply.hop();
c.send(reply);
c.flush();
}
///////////////////////// NO Actual Tests ////////////////////////////
//////////////////////////////////////////////////////////////////
protected void drainAll() throws Exception {
drainAll(testUP);
}
private static void shutdown() throws IOException {
//System.out.println("\nShutting down.");
debug("-Shutting down");
try {
Thread.sleep(2000);
} catch (InterruptedException e) { }
}
/** Marks the Responses of QueryReply as NOT spam */
protected void markAsNotSpam(QueryReply qr) throws Exception {
SpamManager.instance().clearFilterData(); // Start from scratch
Response[] resp = qr.getResultsArray();
RemoteFileDesc rfds[] = new RemoteFileDesc[resp.length];
for(int i = 0; i < resp.length; i++) {
rfds[i] = resp[i].toRemoteFileDesc(qr.getHostData());
//assertTrue(SpamManager.instance().isSpam(rfds[i]));
}
SpamManager.instance().handleUserMarkedGood(rfds);
// Make sure they're not spam
for(int i = 0; i < rfds.length; i++) {
assertFalse(SpamManager.instance().isSpam(rfds[i]));
}
}
protected static boolean DEBUG = false;
protected static void debug(String message) {
if(DEBUG)
System.out.println(message);
}
private static class UltrapeerResponder implements HandshakeResponder {
public HandshakeResponse respond(HandshakeResponse response,
boolean outgoing) {
Properties props = new UltrapeerHeaders("127.0.0.1");
props.put(HeaderNames.X_DEGREE, "42");
return HandshakeResponse.createResponse(props);
}
public void setLocalePreferencing(boolean b) {}
}
private static class OldResponder implements HandshakeResponder {
public HandshakeResponse respond(HandshakeResponse response,
boolean outgoing) {
Properties props=new Properties();
return HandshakeResponse.createResponse(props);
}
public void setLocalePreferencing(boolean b) {}
}
}