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) {} } }