package net.tomp2p.holep.manual; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import net.tomp2p.connection.PeerConnection; import net.tomp2p.futures.FutureDirect; import net.tomp2p.futures.FutureDiscover; import net.tomp2p.nat.PeerBuilderNAT; import net.tomp2p.nat.PeerNAT; import net.tomp2p.p2p.Peer; import net.tomp2p.peers.Number160; import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerSocketAddress; import net.tomp2p.peers.PeerSocketAddress.PeerSocket4Address; import net.tomp2p.relay.Forwarder; import net.tomp2p.relay.RelayCallback; import net.tomp2p.rpc.ObjectDataReply; //travis-ci cannot test this, the kernel does not support all the required features: //Perhaps iptables or your kernel needs to be upgraded //see also here: https://github.com/travis-ci/travis-ci/issues/1341 @Ignore public class TestNATRelay implements Serializable { private static final long serialVersionUID = 1L; final static private Random RND = new Random(42); static private Number160 relayPeerId1 = new Number160(RND); static private Number160 relayPeerId2 = new Number160(RND); static private Number160 relayPeerId3 = new Number160(RND); static private Number160 relayPeerId4 = new Number160(RND); static private Number160 relayPeerId5 = new Number160(RND); //### CHANGE THIS TO YOUR INTERFACE### final static private String INF = "enp0s25"; @Before public void before() throws IOException, InterruptedException { LocalNATUtils.executeNatSetup("start", "0", "sym"); LocalNATUtils.executeNatSetup("start", "1", "sym"); } @After public void after() throws IOException, InterruptedException { LocalNATUtils.executeNatSetup("stop", "0"); LocalNATUtils.executeNatSetup("stop", "1"); } /** * Test if a relay goes offline to contact a new relay. The following cases are tested: * * 1 relay, 1 goes offline, 1 new relay joins, find new relay, add this relay. This test is time sensitive. * * @throws Exception */ @Test public void testRelayFailover1() throws Exception { Peer relayPeer1 = null; Peer relayPeer2 = null; RemotePeer unr1 = null; try { relayPeer1 = createRelay(relayPeerId1, 5002); relayPeer2 = createRelay(relayPeerId2, 5003); final PeerSocket4Address relayAddress1 = relayPeer1.peerAddress().ipv4Socket(); final PeerSocket4Address relayAddress2 = relayPeer2.peerAddress().ipv4Socket(); final Peer relayPeer1Copy = relayPeer1; CommandSync sync = new CommandSync(1); unr1 = LocalNATUtils.executePeer(0, new RemotePeerCallback() { @Override public void onNull(int i) {} @Override public void onFinished(int i) { if(i==0) { //shutdown relay1 System.out.println("go offline!"); relayPeer1Copy.shutdown().awaitUninterruptibly(); } } }, sync, new Command() { @Override public Serializable execute() throws Exception { Peer peer1 = LocalNATUtils.createNattedPeer("10.0.0.2", 5000, 0, "me1"); put("p1", peer1); FutureDiscover fd1 = peer1.discover().peerSocketAddress(relayAddress1).start().awaitUninterruptibly(); Assert.assertFalse(fd1.isDiscoveredTCP()); final CountDownLatch cl1 = new CountDownLatch(1); final CountDownLatch cl2 = new CountDownLatch(1); put("cl2", cl2); PeerNAT pn1 = new PeerBuilderNAT(peer1).relayCallback(countDownRelayCallback2(cl1, cl2)).start(); //setup relay pn1.startRelay(); cl1.await(); //make sure no further relays are searched in the next 5 sec. Check manually! return "shutdown relay1"; } }, new Command() { @Override public Serializable execute() throws Exception { final Peer peer1 = (Peer) get("p1"); //discover the 2nd relay peer1.discover().peerSocketAddress(relayAddress2).start().awaitUninterruptibly(); System.out.println("now we know peer realy2 "); final CountDownLatch cl2 = (CountDownLatch) get("cl2"); cl2.await(); return "done"; } }, new Command() { @Override public Serializable execute() throws Exception { System.err.println("shutdown0"); Thread.sleep(500); return LocalNATUtils.shutdown((Peer)get("p1")); } }); unr1.waitFor(); Assert.assertEquals("done", unr1.getResult(1)); } finally { System.out.print("LOCAL> shutdown."); LocalNATUtils.shutdown(relayPeer1, relayPeer2); System.out.print("."); LocalNATUtils.shutdown(unr1); System.out.println("."); } } /** * Test if a relay goes offline to contact a new relay. The following cases are tested: * * 2 relays, 1 goes offline, switch to the other one * * @throws Exception */ @Test public void testRelayFailover2() throws Exception { Peer relayPeer1 = null; Peer relayPeer2 = null; RemotePeer unr1 = null; try { relayPeer1 = createRelay(relayPeerId1, 5002); final PeerSocket4Address relayAddress1 = relayPeer1.peerAddress().ipv4Socket(); relayPeer2 = createRelay(relayPeerId2, 5003); final PeerSocket4Address relayAddress2 = relayPeer2.peerAddress().ipv4Socket(); final Peer relayPeer1Copy = relayPeer1; final Peer relayPeer2Copy = relayPeer2; final AtomicBoolean test = new AtomicBoolean(false); CommandSync sync = new CommandSync(1); unr1 = LocalNATUtils.executePeer(0, new RemotePeerCallback() { @Override public void onNull(int i) {} @Override public void onFinished(int i) { if(i==0) { //shutdown relay1 System.out.println("go offline!"); relayPeer1Copy.shutdown().awaitUninterruptibly(); } else if(i==1) { Forwarder fw = relayPeer2Copy.connectionBean().dispatcher().searchHandler(Forwarder.class, relayPeer2Copy.peerID() , Number160.createHash(0)); System.out.println("SIIIZE: " + fw.getPeerMap().size()); test.set(fw.getPeerMap().size() == 1); } } }, sync, new Command() { @Override public Serializable execute() throws Exception { Peer peer1 = LocalNATUtils.createNattedPeer("10.0.0.2", 5000, 0, "me1"); put("p1", peer1); FutureDiscover fd1 = peer1.discover().peerSocketAddress(relayAddress1).start().awaitUninterruptibly(); FutureDiscover fd2 = peer1.discover().peerSocketAddress(relayAddress2).start().awaitUninterruptibly(); Assert.assertFalse(fd1.isDiscoveredTCP()); Assert.assertFalse(fd2.isDiscoveredTCP()); final CountDownLatch cl = new CountDownLatch(2); PeerNAT pn1 = new PeerBuilderNAT(peer1).relayCallback(countDownRelayCallback(cl)).start(); //setup relay pn1.startRelay(); cl.await(); //make sure no further relays are searched in the next 5 sec. Check manually! return "shutdown relay1"; } }, new Command() { @Override public Serializable execute() throws Exception { System.out.println("wait 5 sec"); Thread.sleep(7000); System.out.println("done wait 5 sec"); //now relay1 is shutdown, check if we updated our data return "check relay2"; } }, new Command() { @Override public Serializable execute() throws Exception { System.err.println("shutdown0"); Thread.sleep(500); return LocalNATUtils.shutdown((Peer)get("p1")); } }); unr1.waitFor(); Assert.assertTrue(test.get()); } finally { System.out.print("LOCAL> shutdown."); LocalNATUtils.shutdown(relayPeer1, relayPeer2); System.out.print("."); LocalNATUtils.shutdown(unr1); System.out.println("."); } } /** * Test if we wait if we have all relay peers * @throws Exception */ @Test public void testFullRelay() throws Exception { Peer relayPeer1 = null; Peer relayPeer2 = null; Peer relayPeer3 = null; Peer relayPeer4 = null; Peer relayPeer5 = null; RemotePeer unr1 = null; try { relayPeer1 = createRelay(relayPeerId1, 5002); final PeerSocket4Address relayAddress1 = relayPeer1.peerAddress().ipv4Socket(); relayPeer2 = createRelay(relayPeerId2, 5003); final PeerSocket4Address relayAddress2 = relayPeer2.peerAddress().ipv4Socket(); relayPeer3 = createRelay(relayPeerId3, 5004); final PeerSocket4Address relayAddress3 = relayPeer3.peerAddress().ipv4Socket(); relayPeer4 = createRelay(relayPeerId4, 5005); final PeerSocket4Address relayAddress4 = relayPeer4.peerAddress().ipv4Socket(); relayPeer5 = createRelay(relayPeerId5, 5006); final PeerSocket4Address relayAddress5 = relayPeer5.peerAddress().ipv4Socket(); CommandSync sync = new CommandSync(1); unr1 = LocalNATUtils.executePeer(0, sync, new Command() { @Override public Serializable execute() throws Exception { Peer peer1 = LocalNATUtils.createNattedPeer("10.0.0.2", 5000, 0, "me1"); put("p1", peer1); FutureDiscover fd1 = peer1.discover().peerSocketAddress(relayAddress1).start().awaitUninterruptibly(); FutureDiscover fd2 = peer1.discover().peerSocketAddress(relayAddress2).start().awaitUninterruptibly(); FutureDiscover fd3 = peer1.discover().peerSocketAddress(relayAddress3).start().awaitUninterruptibly(); FutureDiscover fd4 = peer1.discover().peerSocketAddress(relayAddress4).start().awaitUninterruptibly(); FutureDiscover fd5 = peer1.discover().peerSocketAddress(relayAddress5).start().awaitUninterruptibly(); Assert.assertFalse(fd1.isDiscoveredTCP()); Assert.assertFalse(fd2.isDiscoveredTCP()); Assert.assertFalse(fd3.isDiscoveredTCP()); Assert.assertFalse(fd4.isDiscoveredTCP()); Assert.assertFalse(fd5.isDiscoveredTCP()); final CountDownLatch cl = new CountDownLatch(1); PeerNAT pn1 = new PeerBuilderNAT(peer1).relayCallback(countDownRelayCallbackFull(cl)).start(); //setup relay pn1.startRelay(); cl.await(); //make sure no further relays are searched in the next 5 sec. Check manually! Thread.sleep(5000); return "done"; } }, new Command() { @Override public Serializable execute() throws Exception { System.err.println("shutdown0"); Thread.sleep(500); return LocalNATUtils.shutdown((Peer)get("p1")); } }); unr1.waitFor(); Assert.assertEquals("done", unr1.getResult(0)); } finally { System.out.print("LOCAL> shutdown."); LocalNATUtils.shutdown(relayPeer1, relayPeer2, relayPeer3, relayPeer4, relayPeer5); System.out.print("."); LocalNATUtils.shutdown(unr1); System.out.println("."); } } /** * Test if a new relay that was discovered is added * @throws Exception */ @Test public void testLateRelay() throws Exception { Peer relayPeer1 = null; Peer relayPeer2 = null; RemotePeer unr1 = null; try { relayPeer1 = createRelay(relayPeerId1, 5002); final PeerSocket4Address relayAddress1 = relayPeer1.peerAddress().ipv4Socket(); relayPeer2 = createRelay(relayPeerId2, 5003); final PeerSocket4Address relayAddress2 = relayPeer2.peerAddress().ipv4Socket(); CommandSync sync = new CommandSync(1); unr1 = LocalNATUtils.executePeer(0, sync, new Command() { @Override public Serializable execute() throws Exception { Peer peer1 = LocalNATUtils.createNattedPeer("10.0.0.2", 5000, 0, "me1"); put("p1", peer1); //get to know both relays FutureDiscover fd1 = peer1.discover().peerSocketAddress(relayAddress1).start().awaitUninterruptibly(); Assert.assertFalse(fd1.isDiscoveredTCP()); final CountDownLatch cl = new CountDownLatch(2); PeerNAT pn1 = new PeerBuilderNAT(peer1).relayCallback(countDownRelayCallback(cl)).start(); //setup relay pn1.startRelay(); Thread.sleep(500); FutureDiscover fd2 = peer1.discover().peerSocketAddress(relayAddress2).start().awaitUninterruptibly(); Assert.assertFalse(fd2.isDiscoveredTCP()); cl.await(); return "done"; } }, new Command() { @Override public Serializable execute() throws Exception { System.err.println("shutdown0"); Thread.sleep(500); return LocalNATUtils.shutdown((Peer)get("p1")); } }); unr1.waitFor(); Assert.assertEquals("done", unr1.getResult(0)); } finally { System.out.print("LOCAL> shutdown."); LocalNATUtils.shutdown(relayPeer1, relayPeer2); System.out.print("."); LocalNATUtils.shutdown(unr1); System.out.println("."); } } private Peer createRelay(Number160 relayPeerId, int port) throws Exception { Peer relayPeer = LocalNATUtils.createRealNode(relayPeerId, INF, port); new PeerBuilderNAT(relayPeer).start(); return relayPeer; } private RelayCallback countDownRelayCallback( final CountDownLatch cl) { return new RelayCallback() { @Override public void onRelayRemoved(PeerAddress candidate, PeerConnection object) {} @Override public void onRelayAdded(PeerAddress candidate, PeerConnection object) {cl.countDown();} @Override public void onFailure(Exception e) {e.printStackTrace();} @Override public void onFullRelays(int activeRelays) {} @Override public void onNoMoreRelays(int activeRelays) {} @Override public void onShutdown() {} }; } private RelayCallback countDownRelayCallback2( final CountDownLatch cl1, final CountDownLatch cl2) { return new RelayCallback() { @Override public void onRelayRemoved(PeerAddress candidate, PeerConnection object) {} @Override public void onRelayAdded(PeerAddress candidate, PeerConnection object) { if(cl1.getCount() > 0 ) { cl1.countDown(); } else { cl2.countDown(); } } @Override public void onFailure(Exception e) {e.printStackTrace();} @Override public void onFullRelays(int activeRelays) {} @Override public void onNoMoreRelays(int activeRelays) {} @Override public void onShutdown() {} }; } private RelayCallback countDownRelayCallbackFull( final CountDownLatch cl) { return new RelayCallback() { @Override public void onRelayRemoved(PeerAddress candidate, PeerConnection object) {} @Override public void onRelayAdded(PeerAddress candidate, PeerConnection object) {} @Override public void onFailure(Exception e) {e.printStackTrace();} @Override public void onFullRelays(int activeRelays) {cl.countDown();} @Override public void onNoMoreRelays(int activeRelays) {} @Override public void onShutdown() {} }; } @SuppressWarnings("serial") @Test public void testRealRelayDifferentNAT() throws Exception { Peer relayPeer = null; RemotePeer unr1 = null; RemotePeer unr2 = null; try { relayPeer = createRelay(relayPeerId1, 5002); final PeerSocket4Address relayAddress = relayPeer.peerAddress().ipv4Socket(); CommandSync sync = new CommandSync(2); unr1 = LocalNATUtils.executePeer(0, sync, new Command() { @Override public Serializable execute() throws Exception { Peer peer1 = LocalNATUtils.createNattedPeer("10.0.0.2", 5000, 0, "me1"); put("p1", peer1); FutureDiscover fd1 = peer1.discover().peerSocketAddress(relayAddress).start().awaitUninterruptibly(); Assert.assertFalse(fd1.isDiscoveredTCP()); final CountDownLatch cl = new CountDownLatch(1); PeerNAT pn1 = new PeerBuilderNAT(peer1).relayCallback(countDownRelayCallback(cl)).start(); //setup relay pn1.startRelay(); cl.await(); Thread.sleep(500); PeerAddress peer2 = LocalNATUtils.peerAddress("10.0.1.2", 5000, 1); Collection<PeerSocketAddress> psa = new ArrayList<PeerSocketAddress>(); psa.add(relayAddress); peer2 = peer2.withRelays(psa); FutureDirect fdir1 = peer1.sendDirect(peer2).object("test").start().awaitUninterruptibly(); System.out.println(fdir1.failedReason()); Assert.assertTrue(fdir1.isSuccess()); String result = fdir1.object().toString(); System.out.println("DONE1" + result); return "me2".equals(result) ? "TRUE" : "FALSE"; } }, new Command() { @Override public Serializable execute() throws Exception { System.err.println("shutdown0"); Thread.sleep(500); return LocalNATUtils.shutdown((Peer)get("p1")); } }); unr2 = LocalNATUtils.executePeer(1, sync, new Command() { @Override public Serializable execute() throws Exception { Peer peer1 = LocalNATUtils.createNattedPeer("10.0.1.2", 5000, 1, "me2"); put("p1", peer1); FutureDiscover fd1 = peer1.discover().peerSocketAddress(relayAddress).start().awaitUninterruptibly(); Assert.assertFalse(fd1.isDiscoveredTCP()); final CountDownLatch cl = new CountDownLatch(1); PeerNAT pn1 = new PeerBuilderNAT(peer1).relayCallback(countDownRelayCallback(cl)).start(); //setup relay pn1.startRelay(); cl.await(); Thread.sleep(500); PeerAddress peer2 = LocalNATUtils.peerAddress("10.0.0.2", 5000, 0); Collection<PeerSocketAddress> psa = new ArrayList<PeerSocketAddress>(); psa.add(relayAddress); peer2 = peer2.withRelays(psa); FutureDirect fdir1 = peer1.sendDirect(peer2).object("test").start().awaitUninterruptibly(); System.out.println(fdir1.failedReason()); Assert.assertTrue(fdir1.isSuccess()); String result = fdir1.object().toString(); System.out.println("DONE2 " + result); return "me1".equals(result) ? "TRUE" : "FALSE"; } }, new Command() { @Override public Serializable execute() throws Exception { System.err.println("shutdown1"); Thread.sleep(500); return LocalNATUtils.shutdown((Peer)get("p1")); } }); unr1.waitFor(); unr2.waitFor(); Assert.assertEquals("TRUE", unr1.getResult(0)); Assert.assertEquals("TRUE", unr2.getResult(0)); } finally { System.out.print("LOCAL> shutdown."); LocalNATUtils.shutdown(relayPeer); System.out.print("."); LocalNATUtils.shutdown(unr1, unr2); System.out.println("."); } } @Test public void testRealRelaySameNATNoRelay() throws Exception { RemotePeer unr1 = null; try { CommandSync sync = new CommandSync(1); unr1 = LocalNATUtils.executePeer(0, sync, new Command() { @Override public Serializable execute() throws Exception { Peer peer1 = LocalNATUtils.createNattedPeer("10.0.0.2", 5000, 0, "n/a"); put("p1", peer1); Peer peer2 = LocalNATUtils.createNattedPeer("10.0.0.3", 5001, 1, "me"); put("p2", peer2); PeerNAT pn1 = new PeerBuilderNAT(peer1).start(); PeerNAT pn2 = new PeerBuilderNAT(peer2).start(); //setup relay pn1.startRelay(); pn2.startRelay(); FutureDirect fdir1 = peer1.sendDirect(peer2.peerAddress()).object("test").start().awaitUninterruptibly(); Assert.assertEquals("me", fdir1.object()); //should be direct not over relay return "done"; } }, new Command() { @Override public Serializable execute() throws Exception { return LocalNATUtils.shutdown((Peer)get("p1"), (Peer)get("p2")); } }); unr1.waitFor(); Assert.assertEquals("done", unr1.getResult(0)); } finally { System.out.print("LOCAL> shutdown."); LocalNATUtils.shutdown(unr1); System.out.println("."); } } @SuppressWarnings("serial") @Test public void testRealRelaySameNAT() throws Exception { Peer relayPeer = null; RemotePeer unr1 = null; try { relayPeer = createRelay(relayPeerId1, 5002); final PeerSocket4Address relayAddress = relayPeer.peerAddress().ipv4Socket(); CommandSync sync = new CommandSync(1); unr1 = LocalNATUtils.executePeer(0, sync, new Command() { @Override public Serializable execute() throws Exception { Peer peer1 = LocalNATUtils.createNattedPeer("10.0.0.2", 5000, 0, "n/a"); put("p1", peer1); Peer peer2 = LocalNATUtils.createNattedPeer("10.0.0.3", 5001, 1, "me"); put("p2", peer2); peer1.discover().peerSocketAddress(relayAddress).start().awaitUninterruptibly(); peer2.discover().peerSocketAddress(relayAddress).start().awaitUninterruptibly(); final CountDownLatch cl = new CountDownLatch(2); PeerNAT pn1 = new PeerBuilderNAT(peer1).relayCallback(countDownRelayCallback(cl)).start(); PeerNAT pn2 = new PeerBuilderNAT(peer2).relayCallback(countDownRelayCallback(cl)).start(); //setup relay pn1.startRelay(); pn2.startRelay(); cl.await(); //send message from p1 to p2 peer2.objectDataReply(new ObjectDataReply() { @Override public Object reply(PeerAddress sender, Object request) throws Exception { return "me"; } }); FutureDirect fdir1 = peer1.sendDirect(peer2.peerAddress()).object("test").start().awaitUninterruptibly(); Assert.assertEquals("me", fdir1.object()); //should be direct not over relay return "done"; } }, new Command() { @Override public Serializable execute() throws Exception { return LocalNATUtils.shutdown((Peer)get("p1"), (Peer)get("p2")); } }); unr1.waitFor(); Assert.assertEquals("done", unr1.getResult(0)); } finally { System.out.print("LOCAL> shutdown."); LocalNATUtils.shutdown(relayPeer); System.out.print("."); LocalNATUtils.shutdown(unr1); System.out.println("."); } } }