package com.limegroup.gnutella; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.net.DatagramPacket; 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.messages.BadPacketException; import com.limegroup.gnutella.messages.Message; import com.limegroup.gnutella.messages.PingRequest; import com.limegroup.gnutella.messages.QueryRequest; import com.limegroup.gnutella.messages.vendor.CapabilitiesVM; import com.limegroup.gnutella.messages.vendor.HopsFlowVendorMessage; import com.limegroup.gnutella.messages.vendor.MessagesSupportedVendorMessage; import com.limegroup.gnutella.messages.vendor.TCPConnectBackVendorMessage; import com.limegroup.gnutella.messages.vendor.UDPConnectBackVendorMessage; import com.limegroup.gnutella.messages.vendor.VendorMessage; import com.limegroup.gnutella.routing.QueryRouteTable; import com.limegroup.gnutella.routing.RouteTableMessage; import com.limegroup.gnutella.settings.ConnectionSettings; import com.limegroup.gnutella.util.BaseTestCase; import com.limegroup.gnutella.util.EmptyResponder; public class VendorMessageSupportTest extends BaseTestCase { private String _remoteHost = "localhost"; private int _remotePort = Backend.BACKEND_PORT; private static final int TIMEOUT = 2*500; private boolean _localTest = true; public VendorMessageSupportTest(String name) { super(name); } public VendorMessageSupportTest(String name, String host, int port) { this(name); _remoteHost = host; _remotePort = port; _localTest = false; } public static Test suite() { return buildTestSuite(VendorMessageSupportTest.class); } private ServerSocket _tcpSock = null; private DatagramSocket _udpSock = null; private Connection _leaf1 = null; private Connection _leaf2 = null; private static boolean _testHopsFlow = true; private static boolean _testTCPCB = true; private static boolean _testUDPCB = true; public void setUp() throws Exception { debug("Expecting to test Gnutella host on " + _remoteHost + ":" + _remotePort); if ( _localTest ) launchBackend(); ConnectionSettings.LOCAL_IS_PRIVATE.setValue(false); // Set up a TCP Listening socket.... _tcpSock = new ServerSocket(0); _tcpSock.setReuseAddress(true); // Set up a UDP Listening socket.... _udpSock = new DatagramSocket(); _udpSock.setReuseAddress(true); // Set up QRT QueryRouteTable qrt = new QueryRouteTable(); qrt.add("susheel"); qrt.add("daswani"); qrt.add("foosball"); // Set up a connection to the host.... _leaf1=new Connection(_remoteHost, _remotePort); _leaf1.initialize(new LeafHeaders(""), new EmptyResponder()); for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) _leaf1.send((RouteTableMessage)iter.next()); _leaf1.flush(); // don't do postInit() - you don't want him thinking // you support any vendor message.... // Set up another connection to the host.... _leaf2=new Connection(_remoteHost, _remotePort); _leaf2.initialize(new LeafHeaders(""), new EmptyResponder()); for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) _leaf2.send((RouteTableMessage)iter.next()); _leaf2.flush(); // don't do postInit() - you don't want him thinking // you support any vendor message.... } public void tearDown() throws Exception { if ( _leaf1 != null ) _leaf1.close(); if ( _leaf2 != null ) _leaf2.close(); if ( _tcpSock != null ) _tcpSock.close(); if ( _udpSock != null ) _udpSock.close(); } public void testConfirmSupportedMessages() throws Exception { testConnection(_leaf1); } private void testConnection(Connection c) throws Exception { boolean receivedDesiredMessage = false; while (true) { try { Message m = (Message) c.receive(TIMEOUT); if (m instanceof VendorMessage) { if (m instanceof MessagesSupportedVendorMessage) { c.handleVendorMessage((VendorMessage) m); receivedDesiredMessage = true; } else if (m instanceof CapabilitiesVM) { // this is expected.... } else fail("Unexpected VendorMessage of class" + m.getClass()); } } catch (InterruptedIOException iioe) { break; // received all messages it seems.... } catch (Exception ignoreOthers) {} } if (!receivedDesiredMessage) fail("No MessagesSupportedMessage recieved"); if (c.supportsVendorMessage("BEAR".getBytes(), 4) < 1) { _testHopsFlow = false; } if (c.supportsVendorMessage("GTKG".getBytes(), 7) < 1) { _testUDPCB = false; } if (c.supportsVendorMessage("BEAR".getBytes(), 7) < 1) { _testTCPCB = false; } } public void testHopsFlow() throws Exception { if ( !_testHopsFlow ) fail("hops flow not supported - ignoring test."); drain(_leaf1); drain(_leaf2); QueryRequest qr = QueryRequest.createQuery("susheel", (byte)3); // first make sure query gets through..... _leaf2.send(qr); _leaf2.flush(); boolean gotQR = false; while (true) { try { Message m = _leaf1.receive(TIMEOUT); if (m instanceof QueryRequest) if (((QueryRequest) m).getQuery().equals("susheel")) gotQR = true; } catch (InterruptedIOException e) { break; // cool, what we want.... } catch (BadPacketException e) {} catch (IOException ioe) {} } if (!gotQR) fail("Did not get expected QR 1!!"); // now send the hops flow and it shouldn't get through!! HopsFlowVendorMessage hops = new HopsFlowVendorMessage((byte)1); _leaf1.send(hops); _leaf1.flush(); // wait for the hops flow message to take effect... try { Thread.sleep(500); } catch (Exception whatever) {} qr = QueryRequest.createQuery("daswani", (byte)3); _leaf2.send(qr); _leaf2.flush(); while (true) { try { Message m = _leaf1.receive(TIMEOUT); if (m instanceof QueryRequest) if (((QueryRequest) m).getQuery().equals("daswani")) fail("Hops Flow message Ineffectual!!!"); } catch (InterruptedIOException e) { break; // cool, what we want.... } catch (BadPacketException e) {} catch (IOException ioe) {} } // reset Hops Flow and make sure a query gets through.... hops = new HopsFlowVendorMessage((byte)4); _leaf1.send(hops); _leaf1.flush(); try { // wait for hops flow to be turned off.... Thread.sleep(2*1000); } catch (InterruptedException ignored) {} qr = QueryRequest.createQuery("foosball", (byte)3); _leaf2.send(qr); _leaf2.flush(); gotQR = false; while (true) { try { Message m = _leaf1.receive(TIMEOUT); if (m instanceof QueryRequest) if (((QueryRequest) m).getQuery().equals("foosball")) gotQR = true; } catch (InterruptedIOException e) { break; // cool, what we want.... } catch (BadPacketException e) {} catch (IOException ioe) {} } if (!gotQR) fail("Did not get expected QR 2!!"); } public void testTCPConnectBack() throws Exception { if (!_testTCPCB) fail("TCP ConnectBack not supported - ignoring test."); drain(_leaf1); drain(_leaf2); _tcpSock.setSoTimeout(5*1000); // wait for up to 5 seconds... final TCPConnectBackVendorMessage tcp = new TCPConnectBackVendorMessage(_tcpSock.getLocalPort()); final Connection c = _leaf1; Thread sendThread = new Thread() { public void run() { try { sleep(2*1000); } catch (InterruptedException whatever) {} try { c.send(tcp); c.flush(); } catch (Exception e) { fail("Couldn't send tcp!!", e); } } }; sendThread.start(); try { _tcpSock.accept(); // wait for the TCP ConnectBack... fail("Did recieve TCP ConnectBack!!"); } catch (Exception good) { } // we be golden dawg!!! } public void testUDPConnectBack() throws Exception { if(!_testUDPCB) fail("UDP Connectback not supported - ignoring test"); drain(_leaf1); drain(_leaf2); _udpSock.setSoTimeout(5*1000); // wait for up to 5 seconds... GUID guid = new GUID(GUID.makeGuid()); DatagramPacket dp = new DatagramPacket(new byte[200], 200); final UDPConnectBackVendorMessage udp = new UDPConnectBackVendorMessage(_udpSock.getLocalPort(), guid); final Connection c = _leaf1; Thread sendThread = new Thread() { public void run() { try { sleep(2*1000); } catch (InterruptedException whatever) {} try { c.send(udp); c.flush(); } catch (Exception e) { fail("Couldn't send udp!!", e); } } }; sendThread.start(); PingRequest pr = null; try { _udpSock.receive(dp); // wait for the UDP ConnectBack... ByteArrayInputStream bais = new ByteArrayInputStream(dp.getData()); pr = (PingRequest) Message.read(bais); fail("Did recieve UDP ConnectBack!!"); } catch (Exception good) { } // we be golden dawg!!! } private static final boolean debugOn = false; private static final void debug(Exception e) { if (debugOn) e.printStackTrace(); } private static final void debug(String out) { if (debugOn) System.out.println(out); } public static void main(String[] argv) throws Exception { if (argv.length != 2) junit.textui.TestRunner.run(suite()); else { String name = VendorMessageSupportTest.class.getName(); String host = argv[0]; int port = Integer.parseInt(argv[1]); junit.textui.TestRunner.run(new VendorMessageSupportTest(name, host, port)); } } }