package net.tomp2p.holep; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import net.tomp2p.connection.Dispatcher; import net.tomp2p.connection.NATHandler; import net.tomp2p.connection.PeerConnection; import net.tomp2p.futures.BaseFutureAdapter; import net.tomp2p.futures.FutureDone; import net.tomp2p.futures.FutureResponse; import net.tomp2p.futures.Futures; import net.tomp2p.holep.strategy.HolePStrategy; import net.tomp2p.message.Message; import net.tomp2p.p2p.Peer; import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerSocketAddress; import net.tomp2p.rpc.RPC; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Jonas Wagner * * This class is created if "new PeerNAT()" is called on a {@link Peer}. This class makes sure that hole * punching is possible. */ public class NATHandlerImpl implements NATHandler { private static final Logger LOG = LoggerFactory.getLogger(NATHandlerImpl.class); private final NATTypeDetection natTypeDetection; private final Peer peer; private boolean testCase = false; private FutureDone<NATType> future; public NATHandlerImpl(final Peer peer) { this.peer = peer; this.natTypeDetection = null; } @Override public FutureDone<Message> handleHolePunch(final int idleUDPMillis, final FutureResponse futureResponse, final Message originalMessage) { //this is called from the sender, we start hole punching here. final FutureDone<Message> futureDone = new FutureDone<Message>(); //final HolePStrategy holePuncher = natType().holePuncher(peer, peer.peerBean().holePNumberOfHoles(), idleUDPSeconds, originalMessage); //return holePuncher.initiateHolePunch(futureDone, futureResponse); return null; } /** * CheckNatType will trigger the {@link NATTypeDetection} object to ping the given relay peer in order to * find out the {@link NATType} of this {@link Peer}. * * @param peerAddress */ public FutureDone<NATType> checkNatType(final PeerAddress peerAddress) { //future = natTypeDetection.checkNATType(peerAddress); return null; //return future; } public boolean isTestCase() { return testCase; } public void testCase(final boolean testCase) { this.testCase = testCase; } @Override public List<FutureResponse> handleRcon(final Dispatcher dispatcher, final Message message, final FutureResponse futureResponse, PeerConnection peerConnection, int idleUDPMillis, ScheduledExecutorService executorService) { int i = 0; dispatcher.addPendingRequest(message.messageId(), futureResponse, idleUDPMillis * 2, executorService); List<FutureResponse> futures = new ArrayList<FutureResponse>(3); for (PeerSocketAddress psa : peerConnection.remotePeer().relays()) { Message rconMessage = createRconMessage(psa, message); FutureResponse fr1 = new FutureResponse(rconMessage); futures.add(fr1); if (++i > 3) { break; } } Futures.<FutureResponse>whenAnySuccess(futures).addListener( new BaseFutureAdapter<FutureDone<FutureResponse>>() { @Override public void operationComplete(FutureDone<FutureResponse> future) throws Exception { if (future.isFailed()) { futureResponse.failed(future); } } }); return futures; } /** * This method makes a copy of the original Message and prepares it for sending it to the relay. * * @param message * @return rconMessage */ private static Message createRconMessage(PeerSocketAddress ps, final Message originalMessage) { Message rconMessage = new Message(); rconMessage.sender(originalMessage.sender()); rconMessage.version(originalMessage.version()); // store the message id in the payload to get the cached message later rconMessage.intValue(originalMessage.messageId()); // making the message ready to send PeerAddress recipient = originalMessage.recipient().withIPSocket(ps).withRelaySize(0); rconMessage.recipient(recipient); rconMessage.command(RPC.Commands.RCON.getNr()); rconMessage.type(Message.Type.REQUEST_1); return rconMessage; } }