In the current system, we use Tunnels to help connectivity in constrained environments. Specifically, we want a ring that has no broken connections and so we use Tunnels to ammeliorate that. There are two issues with Tunnels that I have been poking me. A) Connections support only a single Edge, so once we select an Edge type, we are stuck with it, regardless of how well it performs. Tunnels allow us to add Tunneling proxies, if a Tunnel occurs due to slow NAT traversal, we are stuck with it and this case has been observed! B) Tunnels require the routing logic to be duplicated inside of them. Now granted, the original design of Tunnels couldn't really have an optimized routing algorithm, but as we add more features like proximity routing, it is unenjoyable to maintain two sets of code. Especially one that is more difficult to properly test!
How to deal with A). Let's make X attempt to form direct edges if a Tunnel exists, if we are so lucky to create one, we'll replace the TunnelEdge in the Connection with a non-TunnelEdge. So we need to define who X should be. Another possibility is to let the Tunnel become a wrapper for a direct edge. This way the TunnelEdge[Listener] is responsible for a obtaining that direct connection.
B) is a little trickier, but I think the best approach is to strip from the Tunnel a list of edges to send on and just use standard routing to pass the message to the remote end point. This would be particularly useful if we knew all of our neighbors' neighbors. In fact, we could remove all of the sync in a Tunnel if we had this information. This just requires some leg work.
I reckon, once A and B are handled, using Tunnels for wide area communication won't be such an issue any more.