package com.limegroup.gnutella; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeSet; import junit.framework.Test; import com.limegroup.gnutella.messages.Message; import com.limegroup.gnutella.messages.PushRequest; import com.limegroup.gnutella.settings.ConnectionSettings; import com.limegroup.gnutella.stubs.ActivityCallbackStub; import com.limegroup.gnutella.util.BaseTestCase; import com.limegroup.gnutella.util.IpPort; import com.limegroup.gnutella.util.IpPortImpl; import com.limegroup.gnutella.util.PrivilegedAccessor; import com.limegroup.gnutella.xml.LimeXMLDocument; /** * Tests the issuing of Push Request through udp and failover to tcp. */ public class UDPPushTest extends BaseTestCase { public UDPPushTest(String name) { super(name); } public static Test suite() { return buildTestSuite(UDPPushTest.class); } static RemoteFileDesc rfd1, rfd2,rfdAlt; /** * the socket that will supposedly be the push download */ static Socket socket; /** * the socket that will listen for the tcp push request */ static ServerSocket serversocket; /** * the socket that will listen for the udp push request */ static DatagramSocket udpsocket; static byte [] guid = GUID.fromHexString("BC1F6870696111D4A74D0001031AE043"); public static void globalSetUp() throws Exception { ConnectionSettings.LOCAL_IS_PRIVATE.setValue(false); ConnectionSettings.SOLICITED_GRACE_PERIOD.setValue(5000l); serversocket = new ServerSocket(10000); serversocket.setSoTimeout(1000); udpsocket = new DatagramSocket(20000); udpsocket.setSoTimeout(1000); ActivityCallback ac = new ActivityCallbackStub(); RouterService rs = new RouterService(ac); rs.start(); } public void setUp() { try{ Map map = (Map) PrivilegedAccessor.getValue(RouterService.getDownloadManager(), "UDP_FAILOVER"); map.clear(); }catch(Exception tough){tough.printStackTrace();} long now = System.currentTimeMillis(); Set proxies = new TreeSet(IpPort.COMPARATOR); try { proxies.add(new IpPortImpl(InetAddress.getLocalHost().getHostAddress(),10000)); } catch (UnknownHostException bad) { ErrorService.error(bad); } LimeXMLDocument doc = null; Set urns = null; rfd1 = new RemoteFileDesc( "127.0.0.1",20000,30l,"file1", 100,guid,SpeedConstants.CABLE_SPEED_INT, false,1,false, doc,urns, false,true, "LIME",now, proxies,now); rfd2 = new RemoteFileDesc( "127.0.0.1",20000,31l,"file2", 100,guid,SpeedConstants.CABLE_SPEED_INT, false,1,false, doc,urns, false,true, "LIME",now, proxies,now); rfdAlt = new RemoteFileDesc( "127.0.0.1",20000,30l,"file1", 100,guid,SpeedConstants.CABLE_SPEED_INT, false,1,false, doc,urns, false,true, "ALT",now, proxies,now); Acceptor acc = RouterService.getAcceptor(); try{ PrivilegedAccessor.setValue(acc,"_acceptedIncoming",new Boolean(true)); }catch(Exception bad) { ErrorService.error(bad); } assertTrue(RouterService.acceptedIncomingConnection()); } /** * tests the scenario where an udp push is sent, but no * connection is received so the failover tcp push is sent. */ public void testUDPPushFailover() throws Exception { requestPush(rfd1); try { serversocket.accept(); fail("tcp attempt was made"); }catch(IOException expected){} DatagramPacket push = new DatagramPacket(new byte[1000],1000); udpsocket.receive(push); ByteArrayInputStream bais = new ByteArrayInputStream(push.getData()); PushRequest pr = (PushRequest)Message.read(bais); assertEquals(rfd1.getIndex(),pr.getIndex()); Thread.sleep(5200); Socket s = serversocket.accept(); assertTrue(s.isConnected());s.close(); } /** * tests the scenario where an udp push is sent, no * connection is received but since we're trying to contact * an altloc no failover tcp push is sent. */ public void testUDPPushFailoverAlt() throws Exception { requestPush(rfdAlt); try { serversocket.accept(); fail("tcp attempt was made"); }catch(IOException expected){} DatagramPacket push = new DatagramPacket(new byte[1000],1000); udpsocket.receive(push); ByteArrayInputStream bais = new ByteArrayInputStream(push.getData()); PushRequest pr = (PushRequest)Message.read(bais); assertEquals(rfd1.getIndex(),pr.getIndex()); Thread.sleep(5200); try { Socket s =serversocket.accept(); s.close(); fail("tcp attempt was made"); }catch(IOException expected){} Thread.sleep(3000); } /** * tests the scenario where an UDP push is sent and * a connection is established, so no failover occurs. */ public void testUDPPush() throws Exception { requestPush(rfd1); try { serversocket.accept(); fail("tcp attempt was made"); }catch(IOException expected){} DatagramPacket push = new DatagramPacket(new byte[1000],1000); udpsocket.receive(push); ByteArrayInputStream bais = new ByteArrayInputStream(push.getData()); PushRequest pr = (PushRequest)Message.read(bais); assertEquals(rfd1.getIndex(),pr.getIndex()); socket = new Socket(InetAddress.getLocalHost(),10000); Socket other = serversocket.accept(); assertEquals(InetAddress.getLocalHost(),socket.getInetAddress()); assertEquals(10000,socket.getPort()); sendGiv(other, "0:BC1F6870696111D4A74D0001031AE043/file1\n\n"); RouterService.getDownloadManager().acceptDownload(socket); other.close(); Thread.sleep(5000); try { Socket s =serversocket.accept(); s.close(); fail("tcp attempt was made"); }catch(IOException expected){} Thread.sleep(3000); } /** * tests the scenario where two pushes are made to the same host * for different files and both succeed. */ public void testTwoPushesBothGood() throws Exception{ requestPush(rfd1); requestPush(rfd2); try { serversocket.accept(); fail("tcp attempt was made"); }catch(IOException expected){} DatagramPacket push = new DatagramPacket(new byte[1000],1000); udpsocket.receive(push); ByteArrayInputStream bais = new ByteArrayInputStream(push.getData()); PushRequest pr = (PushRequest)Message.read(bais); assertEquals(rfd1.getIndex(),pr.getIndex()); udpsocket.receive(push); bais = new ByteArrayInputStream(push.getData()); pr = (PushRequest)Message.read(bais); assertEquals(rfd2.getIndex(),pr.getIndex()); Thread.sleep(2000); socket = new Socket(InetAddress.getLocalHost(),10000); Socket other = serversocket.accept(); sendGiv(other, "0:BC1F6870696111D4A74D0001031AE043/file1\n\n"); RouterService.getDownloadManager().acceptDownload(socket); socket.close(); socket = new Socket(InetAddress.getLocalHost(),10000); other = serversocket.accept(); socket.setSoTimeout(1000); sendGiv(other, "0:BC1F6870696111D4A74D0001031AE043/file2\n\n"); RouterService.getDownloadManager().acceptDownload(socket); socket.close(); Thread.sleep(5200); try { serversocket.accept(); fail("tcp attempt was made"); }catch(IOException expected){} } public void testTwoPushesOneFails() throws Exception { requestPush(rfd1); requestPush(rfd2); try { serversocket.accept(); fail("tcp attempt was made"); }catch(IOException expected){} DatagramPacket push = new DatagramPacket(new byte[1000],1000); udpsocket.receive(push); ByteArrayInputStream bais = new ByteArrayInputStream(push.getData()); PushRequest pr = (PushRequest)Message.read(bais); assertEquals(rfd1.getIndex(),pr.getIndex()); udpsocket.receive(push); bais = new ByteArrayInputStream(push.getData()); pr = (PushRequest)Message.read(bais); assertEquals(rfd2.getIndex(),pr.getIndex()); Thread.sleep(2000); socket = new Socket(InetAddress.getLocalHost(),10000); Socket other = serversocket.accept(); sendGiv(other, "0:BC1F6870696111D4A74D0001031AE043/file1\n\n"); RouterService.getDownloadManager().acceptDownload(socket); socket.close(); Thread.sleep(5200); serversocket.accept().close(); } static void requestPush(final RemoteFileDesc rfd) throws Exception{ Thread t = new Thread() { public void run() { RouterService.getDownloadManager().sendPush(rfd); } }; t.start(); Thread.sleep(100); } static void sendGiv(final Socket sock,final String str) { Thread t = new Thread() { public void run() { try { sock.getOutputStream().write(str.getBytes()); }catch(IOException e) { fail(e); } } }; t.start(); } }