summaryrefslogtreecommitdiff
path: root/node/Peer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'node/Peer.cpp')
-rw-r--r--node/Peer.cpp63
1 files changed, 38 insertions, 25 deletions
diff --git a/node/Peer.cpp b/node/Peer.cpp
index 24e3c869..86a0da0f 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -121,18 +121,23 @@ bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,u
{
Mutex::Lock _l(_lock);
+ /* For sending ordinary packets, paths are divided into two categories:
+ * "normal" and "TCP out." Normal includes UDP and incoming TCP. We want
+ * to treat outbound TCP differently since if we use it it may end up
+ * overriding UDP and UDP performs much better. We only want to initiate
+ * TCP if it looks like UDP isn't available. */
Path *bestNormalPath = (Path *)0;
Path *bestTcpOutPath = (Path *)0;
uint64_t bestNormalPathLastReceived = 0;
uint64_t bestTcpOutPathLastReceived = 0;
for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) {
uint64_t lr = p->lastReceived();
- if (p->type() == Path::PATH_TYPE_TCP_OUT) { // TCP_OUT paths initiate TCP connections
+ if (p->type() == Path::PATH_TYPE_TCP_OUT) {
if (lr >= bestTcpOutPathLastReceived) {
bestTcpOutPathLastReceived = lr;
bestTcpOutPath = &(*p);
}
- } else { // paths other than TCP_OUT are considered "normal"
+ } else {
if (lr >= bestNormalPathLastReceived) {
bestNormalPathLastReceived = lr;
bestNormalPath = &(*p);
@@ -141,20 +146,23 @@ bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,u
}
Path *bestPath = (Path *)0;
- if (!_r->tcpTunnelingEnabled) { // TCP tunneling master switch is off, use normal path
+ if (bestTcpOutPath) { // we have a TCP out path
+ if (bestNormalPath) { // we have both paths, decide which to use
+ if (_r->tcpTunnelingEnabled) { // TCP tunneling is enabled, so use normal path only if it looks alive
+ if ((bestNormalPathLastReceived > _r->timeOfLastResynchronize)&&((now - bestNormalPathLastReceived) < ZT_PEER_PATH_ACTIVITY_TIMEOUT))
+ bestPath = bestNormalPath;
+ else bestPath = bestTcpOutPath;
+ } else { // TCP tunneling is disabled, use normal path
+ bestPath = bestNormalPath;
+ }
+ } else { // we only have a TCP_OUT path, so use it regardless
+ bestPath = bestTcpOutPath;
+ }
+ } else { // we only have a normal path (or none at all, that case is caught below)
bestPath = bestNormalPath;
- } else if (bestNormalPath) { // we have a normal path, so use if it looks active
- if ((bestNormalPathLastReceived > _r->timeOfLastResynchronize)&&((now - bestNormalPathLastReceived) < ZT_PEER_PATH_ACTIVITY_TIMEOUT))
- bestPath = bestNormalPath;
- else bestPath = bestTcpOutPath;
- } else { // no normal path available
- bestPath = bestTcpOutPath;
}
- if (!bestPath)
- return false;
-
- if (_r->sm->send(bestPath->address(),bestPath->tcp(),bestPath->type() == Path::PATH_TYPE_TCP_OUT,data,len)) {
+ if ((bestPath)&&(_r->sm->send(bestPath->address(),bestPath->tcp(),bestPath->type() == Path::PATH_TYPE_TCP_OUT,data,len))) {
bestPath->sent(now);
return true;
}
@@ -167,8 +175,10 @@ bool Peer::sendFirewallOpener(const RuntimeEnvironment *_r,uint64_t now)
Mutex::Lock _l(_lock);
for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) {
- if (!p->tcp())
- sent |= _r->sm->sendFirewallOpener(p->address(),ZT_FIREWALL_OPENER_HOPS);
+ if (p->type() == Path::PATH_TYPE_UDP) {
+ for(unsigned int h=1;h<=ZT_FIREWALL_OPENER_HOPS;++h)
+ sent |= _r->sm->sendFirewallOpener(p->address(),h);
+ }
}
return sent;
@@ -180,23 +190,26 @@ bool Peer::sendPing(const RuntimeEnvironment *_r,uint64_t now)
SharedPtr<Peer> self(this);
Mutex::Lock _l(_lock);
- uint64_t lastUdpPingSent = 0;
- uint64_t lastUdpReceive = 0;
- bool haveUdp = false;
+ /* Ping (and thus open) outbound TCP connections if we have no other options
+ * or if the TCP tunneling master switch is enabled and pings have been
+ * unanswered for ZT_TCP_TUNNEL_FAILOVER_TIMEOUT ms over normal channels. */
+ uint64_t lastNormalPingSent = 0;
+ uint64_t lastNormalReceive = 0;
+ bool haveNormal = false;
for(std::vector<Path>::const_iterator p(_paths.begin());p!=_paths.end();++p) {
- if (p->type() == Path::PATH_TYPE_UDP) {
- lastUdpPingSent = std::max(lastUdpPingSent,p->lastPing());
- lastUdpReceive = std::max(lastUdpReceive,p->lastReceived());
- haveUdp = true;
+ if (p->type() != Path::PATH_TYPE_TCP_OUT) {
+ lastNormalPingSent = std::max(lastNormalPingSent,p->lastPing());
+ lastNormalReceive = std::max(lastNormalReceive,p->lastReceived());
+ haveNormal = true;
}
}
- bool useTcpOut = ( (!haveUdp) || ( (_r->tcpTunnelingEnabled) && (lastUdpPingSent > lastUdpReceive) && ((now - lastUdpReceive) >= ZT_TCP_TUNNEL_FAILOVER_TIMEOUT) ) );
+ const bool useTcpOut = ( (!haveNormal) || ( (_r->tcpTunnelingEnabled) && (lastNormalPingSent > _r->timeOfLastResynchronize) && (lastNormalPingSent > lastNormalReceive) && ((lastNormalPingSent - lastNormalReceive) >= ZT_TCP_TUNNEL_FAILOVER_TIMEOUT) ) );
TRACE("PING %s (useTcpOut==%d)",_id.address().toString().c_str(),(int)useTcpOut);
for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) {
if ((useTcpOut)||(p->type() != Path::PATH_TYPE_TCP_OUT)) {
- p->pinged(now); // we log pings sent even if the send "fails", since what we want to track is when we last tried to ping
+ p->pinged(now); // attempts to ping are logged whether they look successful or not
if (_r->sw->sendHELLO(self,*p)) {
p->sent(now);
sent = true;
@@ -212,7 +225,7 @@ void Peer::clean(uint64_t now)
Mutex::Lock _l(_lock);
unsigned long i = 0,o = 0,l = (unsigned long)_paths.size();
while (i != l) {
- if (_paths[i].active(now))
+ if (_paths[i].active(now)) // active includes fixed
_paths[o++] = _paths[i];
++i;
}