TomP2P allows to automatically set up NAT traversal. If a peer is not reachable by its external address, the TomP2P will first try to set up port forwarding on the router using UPNP and NATPMP. If that fails, TomP2P allows setting up distributed relaying.
The discovery procedure makes sure that the peer knows how it is seen by other peers, and whether or not it is reachable from outside the LAN.
In order to optain this information, a peer first sends a ping to any known peer. The other peer then reports back how the peer is seen from outside the LAN. After that, a probe is sent to the new peer, to test wether the new peer is reachable by its external address. If the probe succeeded, the peer can bootstrap and participate in the network.
If the probe failed, the unreachable peer can try to set up port forwarding with UPNP and NATPMP. If that failed as well, as a last measure the peer will set up relay peers that forward all messages intended for the unreachable peer through an open TCP channel to the unreachable peer.
Random rnd = new Random();
Peer peer = new PeerMaker(new Number160(rnd)).ports(4000).setBehindFirewall().makeAndListen();
PeerNAT peerNAT = new PeerNAT(peer);
PeerAddress pa = new PeerAddress(Number160.ZERO, InetAddress.getByName(ip), 4000, 4000);
//Check if peer is reachable from the internet
FutureDiscover fd = peer.discover().peerAddress(pa).start();
// Try to set up port forwarding with UPNP and NATPMP if peer is not reachable
FutureNAT fn = peerNAT.startSetupPortforwarding(fd);
//if port forwarding failed, this will set up relay peers
FutureRelayNAT frn = peerNAT.startRelay(fn);
fd.awaitUninterruptibly();
frn.awaitUninterruptibly();
//now the peer should be reachable
After that, the peer should be reachable from all peers in any case.
For a more fine-grained set up of the relays, the relay peers can be set up as follows. First, The firewalled flags have to be set, so that other peers don’t add the unreachable peer to their peer maps.
// Set the isFirewalledUDP and isFirewalledTCP flags
PeerAddress upa = unreachablePeer.getPeerBean().serverPeerAddress();
upa = upa.changeFirewalledTCP(true).changeFirewalledUDP(true);
unreachablePeer.getPeerBean().serverPeerAddress(upa);
After that, the unreachable peer has to bootstrap in order to get a list of his close neighbors. Since the peer is flagged as unreachable, other peers won’t include this peer in their peer maps.
// find neighbors
FutureBootstrap futureBootstrap = unreachablePeer.bootstrap().setPeerAddress(bootstrapAddress).start();
futureBootstrap.awaitUninterruptibly();
Now the peer is ready to set up the relays. By calling startSetupRelay()
, the unreachable peer will call the RelayRPC
on its closest neighbors. The RelayRPC
will register a message handler for all messages that are intended for the unreachable peer. The TCP channel that was opened for the procedure call is kept open. If the RelayRPC
call succeeded, the unreachable peer will add the relay’s socket address to its PeerAddress
.
//setup relay
PeerNAT uNat = new PeerNAT(unreachablePeer);
// set up 3 relays
FutureRelay futureRelay = uNat.minRelays(3).startSetupRelay();
rf.awaitUninterruptibly();
By default, the peer tries to set up five relay peers. The relay setup is considered a success if at least three relay peers were set up. From this point on, all messages that are received on any of the relay peer but have the unreachable peer’s peer address as recipient address will be serialized and sent to the unreachable peer through the open TCP channel. The reply message from the unreachable peer is again serialized, and sent back to the relay peer.
The peer is now reachable from the internet, and can now bootstrap again. The isFirewalledTCP and isFirewalledUDP flags are automatically set to false
after the relays have been set up. If a relay fails, the peer will automatically try to set up a new relay peer.
// find neighbors again
FutureBootstrap fb = unreachablePeer.bootstrap().setPeerAddress(bootstrapAddress).start();
fb.awaitUninterruptibly();
Since routing has to be fast, routing messages are not relayed to the unreachable peers, but handled by its relay peers on behalf of the unreachable peer. Therefore, all relay peers need an up-to-date version of the unreachable peer’s peer map. By enabling the maintanace, the unreachable peer will periodically bootstrap to optain an up-to-date peer map, and push the peer map to all its relay peers.
uNat.bootstrapBuilder(unreachablePeer.bootstrap().setPeerAddress(bootstrapAddress));
Shutdown shutdown = uNat.startRelayMaintenance(futureRelay);
The following options for the relays are available:
relays(Collection<PeerAddress>)
: Defines which peers should be used as relays. With this option, a stable server can be used as a default relayminRelays(in)
: Minimum number of relays that have to be set up to be considered a successmaxRelays(int)
: How many relays the unreachable peer should set upmaxFail(int)
: The upper bound of how times setting up a relay can fail before it is considered a failpeerMapUpdateInterval(int)
: How many times the unreachable peer should push its peer map to its relay peersbootstrapBuilder(BootstrapBuilder)
: The bootstrap builder that is used to bootstrap during the set up of the relays, as well as after the set up for optaining the current peer map