package com.limegroup.gnutella; import java.io.IOException; import java.io.OutputStream; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Socket; import java.util.Set; import junit.framework.Test; import com.limegroup.gnutella.messages.BadPacketException; import com.limegroup.gnutella.messages.Message; import com.limegroup.gnutella.messages.QueryReply; import com.limegroup.gnutella.messages.QueryRequest; import com.limegroup.gnutella.messages.vendor.MessagesSupportedVendorMessage; import com.limegroup.gnutella.messages.vendor.QueryStatusResponse; import com.limegroup.gnutella.search.HostData; import com.limegroup.gnutella.stubs.ActivityCallbackStub; import com.limegroup.gnutella.util.PrivilegedAccessor; import com.limegroup.gnutella.util.Sockets; /** * Checks whether (multi)leaves avoid forwarding messages to ultrapeers, do * redirects properly, etc. The test includes a leaf attached to 3 * Ultrapeers. */ public class ClientSideMixedOOBGuidanceTest extends ClientSideTestCase { /** * Ultrapeer 1 UDP connection. */ private static DatagramSocket UDP_ACCESS; public ClientSideMixedOOBGuidanceTest(String name) { super(name); } public static Test suite() { return buildTestSuite(ClientSideMixedOOBGuidanceTest.class); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** @return The first QueryRequest received from this connection. If null * is returned then it was never recieved (in a timely fashion). */ private static QueryStatusResponse getFirstQueryStatus(Connection c) throws IOException, BadPacketException { return (QueryStatusResponse) getFirstInstanceOfMessageType(c, QueryStatusResponse.class, TIMEOUT); } ///////////////////////// Actual Tests //////////////////////////// // MUST RUN THIS TEST FIRST public void testMixedProtocol() throws Exception { DatagramPacket pack = null; UDP_ACCESS = new DatagramSocket(); for (int i = 0; i < testUP.length; i++) { assertTrue("not open", testUP[i].isOpen()); assertTrue("not up->leaf", testUP[i].isSupernodeClientConnection()); drain(testUP[i], 500); if ((i==2)) { // i'll send 0 later.... testUP[i].send(MessagesSupportedVendorMessage.instance()); testUP[i].flush(); } } testUP[0].send(MessagesSupportedVendorMessage.instance()); testUP[0].flush(); // first we need to set up GUESS capability UDP_ACCESS.setSoTimeout(TIMEOUT*2); // ---------------------------------------- // set up solicited UDP support PrivilegedAccessor.setValue( rs.getUdpService(), "_acceptedSolicitedIncoming", Boolean.TRUE ); // set up unsolicited UDP support PrivilegedAccessor.setValue( rs.getUdpService(), "_acceptedUnsolicitedIncoming", Boolean.TRUE ); // you also have to set up TCP incoming.... { Socket sock = null; OutputStream os = null; try { sock=Sockets.connect(InetAddress.getLocalHost().getHostAddress(), SERVER_PORT, 12); os = sock.getOutputStream(); os.write("\n\n".getBytes()); } catch (IOException ignored) { } catch (SecurityException ignored) { } catch (Throwable t) { ErrorService.error(t); } finally { if(sock != null) try { sock.close(); } catch(IOException ignored) {} if(os != null) try { os.close(); } catch(IOException ignored) {} } } // ---------------------------------------- Thread.sleep(250); // we should now be guess capable and tcp incoming capable.... assertTrue(RouterService.isGUESSCapable()); assertTrue(RouterService.acceptedIncomingConnection()); // get rid of any messages that are stored up. drainAll(); // first of all, we should confirm that we are sending out a OOB query. GUID queryGuid = new GUID(RouterService.newQueryGUID()); assertTrue(GUID.addressesMatch(queryGuid.bytes(), RouterService.getAddress(), RouterService.getPort())); RouterService.query(queryGuid.bytes(), "susheel"); Thread.sleep(250); // some connected UPs should get a OOB query for (int i = 0; i < testUP.length; i++) { QueryRequest qr = getFirstQueryRequest(testUP[i], TIMEOUT); assertNotNull("up " + i + " didn't get query", qr); assertEquals(new GUID(qr.getGUID()), queryGuid); if ((i==0) || (i==2)) assertTrue(qr.desiresOutOfBandReplies()); else assertTrue(!qr.desiresOutOfBandReplies()); } // now confirm that we leaf guide the 'even' guys but not the others. Message m = null; // ensure that we'll get a QueryStatusResponse from the Responses // we're sending. for (int i = 0; i < testUP.length; i++) { Response[] res = new Response[] { // Only the 'susheel' Responses will pass the // ResponseVerifier.matchesQuery() check and // the others wont new Response(10, 10, "susheel"+i), new Response(10, 10, "susheel smells good"+i), new Response(10, 10, "anita is sweet"+i), new Response(10, 10, "anita is prety"+i), new Response(10, 10, "susheel smells bad" + i), new Response(10, 10, "renu is sweet " + i), new Response(10, 10, "prety is spelled pretty " + i), new Response(10, 10, "go susheel go" + i), new Response(10, 10, "susheel runs fast" + i), new Response(10, 10, "susheel jumps high" + i), new Response(10, 10, "sleepy susheel" + i), }; m = new QueryReply(queryGuid.bytes(), (byte) 1, 6355, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // all UPs should get a QueryStatusResponse for (int i = 0; i < testUP.length; i++) { QueryStatusResponse stat = getFirstQueryStatus(testUP[i]); if ((i==0) || (i==2)) { assertNotNull(stat); assertEquals(new GUID(stat.getGUID()), queryGuid); assertEquals(5, stat.getNumResults()); } else assertNull(stat); } // shut off the query.... RouterService.stopQuery(queryGuid); // all UPs should get a QueryStatusResponse with 65535 for (int i = 0; i < testUP.length; i++) { QueryStatusResponse stat = getFirstQueryStatus(testUP[i]); if ((i==0) || (i==2)) { assertNotNull(stat); assertEquals(new GUID(stat.getGUID()), queryGuid); assertEquals(65535, stat.getNumResults()); } else assertNull(stat); } } ////////////////////////////////////////////////////////////////// private static byte[] myIP() { return new byte[] { (byte)127, (byte)0, 0, 1 }; } public static Integer numUPs() { return new Integer(3); } public static ActivityCallback getActivityCallback() { return new MyActivityCallback(); } public static class MyActivityCallback extends ActivityCallbackStub { private RemoteFileDesc rfd = null; public RemoteFileDesc getRFD() { return rfd; } public void handleQueryResult(RemoteFileDesc returnedRfd, HostData data, Set locs) { this.rfd = returnedRfd; } } }