diff options
-rw-r--r-- | include/ZeroTierOne.h | 18 | ||||
-rw-r--r-- | node/Constants.hpp | 2 | ||||
-rw-r--r-- | node/IncomingPacket.hpp | 10 | ||||
-rw-r--r-- | node/Node.cpp | 4 | ||||
-rw-r--r-- | node/Node.hpp | 4 | ||||
-rw-r--r-- | node/Packet.cpp | 1 | ||||
-rw-r--r-- | node/Packet.hpp | 40 | ||||
-rw-r--r-- | node/Path.hpp | 8 | ||||
-rw-r--r-- | node/Peer.hpp | 21 | ||||
-rw-r--r-- | node/Switch.cpp | 183 | ||||
-rw-r--r-- | node/Switch.hpp | 13 |
11 files changed, 162 insertions, 142 deletions
diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 583a75ca..9499bb9b 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -151,12 +151,7 @@ enum ZT1_NodeStatusCode /** * Node is online -- at least one upstream is reachable */ - ZT1_NODE_STATUS_ONLINE = 1, - - /** - * Link desperation level has changed - */ - ZT1_NODE_STATUS_DESPERATION_CHANGE = 3 + ZT1_NODE_STATUS_ONLINE = 1 }; /** @@ -191,7 +186,7 @@ typedef struct /** * Current maximum link desperation metric */ - int desperation; + unsigned int desperation; } ZT1_NodeStatus; /** @@ -394,11 +389,6 @@ typedef struct uint64_t bytesReceived; /** - * This path's desperation metric (higher == worse) - */ - int desperation; - - /** * Is path fixed? (i.e. not learned, static) */ int fixed; @@ -548,7 +538,7 @@ typedef int (*ZT1_DataStorePutFunction)(ZT1_Node *,const char *,const void *,uns * on failure. Note that success does not (of course) guarantee packet * delivery. It only means that the packet appears to have been sent. */ -typedef int (*ZT1_WirePacketSendFunction)(ZT1_Node *,const struct sockaddr_storage *,int,const void *,unsigned int); +typedef int (*ZT1_WirePacketSendFunction)(ZT1_Node *,const struct sockaddr_storage *,unsigned int,const void *,unsigned int); /** * Function to send a frame out to a virtual network port @@ -602,7 +592,7 @@ enum ZT1_ResultCode ZT1_Node_processWirePacket( ZT1_Node *node, uint64_t now, const struct sockaddr_storage *remoteAddress, - int linkDesperation, + unsigned int linkDesperation, const void *packetData, unsigned int packetLength, uint64_t *nextCallDeadline); diff --git a/node/Constants.hpp b/node/Constants.hpp index 8cef29e6..d4944b5e 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -334,7 +334,7 @@ * a RENDEZVOUS message no more than this often. This instructs the peers * to attempt NAT-t and gives each the other's corresponding IP:port pair. */ -#define ZT_MIN_UNITE_INTERVAL 30000 +#define ZT_MIN_UNITE_INTERVAL 60000 /** * Delay between initial direct NAT-t packet and more aggressive techniques diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index a6d2f4cd..ef25fbc4 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -31,14 +31,12 @@ #include <stdexcept> #include "Packet.hpp" -#include "SocketManager.hpp" #include "InetAddress.hpp" #include "Utils.hpp" #include "SharedPtr.hpp" #include "AtomicCounter.hpp" #include "MulticastGroup.hpp" #include "Peer.hpp" -#include "Socket.hpp" /* * The big picture: @@ -73,17 +71,17 @@ public: * Create a new packet-in-decode * * @param b Source buffer with raw packet data - * @param fromSock Socket on which packet was received * @param remoteAddress Address from which packet came + * @param linkDesperation Link desperation for link over which packet was received * @throws std::out_of_range Range error processing packet */ template<unsigned int C2> - IncomingPacket(const Buffer<C2> &b,const SharedPtr<Socket> &fromSock,const InetAddress &remoteAddress) + IncomingPacket(const Buffer<C2> &b,const InetAddress &remoteAddress,unsigned int linkDesperation) throw(std::out_of_range) : Packet(b), _receiveTime(Utils::now()), - _fromSock(fromSock), _remoteAddress(remoteAddress), + _linkDesperation(linkDesperation), __refCount() { } @@ -130,8 +128,8 @@ private: void _sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer,uint64_t nwid); uint64_t _receiveTime; - SharedPtr<Socket> _fromSock; InetAddress _remoteAddress; + unsigned int _linkDesperation; AtomicCounter __refCount; }; diff --git a/node/Node.cpp b/node/Node.cpp index 370e35d6..4297a2ec 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -95,7 +95,7 @@ Node::~Node() ZT1_ResultCode Node::processWirePacket( uint64_t now, const struct sockaddr_storage *remoteAddress, - int linkDesperation, + unsigned int linkDesperation, const void *packetData, unsigned int packetLength, uint64_t *nextCallDeadline) @@ -207,7 +207,7 @@ enum ZT1_ResultCode ZT1_Node_processWirePacket( ZT1_Node *node, uint64_t now, const struct sockaddr_storage *remoteAddress, - int linkDesperation, + unsigned int linkDesperation, const void *packetData, unsigned int packetLength, uint64_t *nextCallDeadline) diff --git a/node/Node.hpp b/node/Node.hpp index 385d60a4..2dbf64b2 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -71,7 +71,7 @@ public: ZT1_ResultCode processWirePacket( uint64_t now, const struct sockaddr_storage *remoteAddress, - int linkDesperation, + unsigned int linkDesperation, const void *packetData, unsigned int packetLength, uint64_t *nextCallDeadline); @@ -113,7 +113,7 @@ public: * @param desperation Link desperation for reaching this address * @return True if packet appears to have been sent */ - inline bool putPacket(const InetAddress &addr,const void *data,unsigned int len,int desperation) + inline bool putPacket(const InetAddress &addr,const void *data,unsigned int len,unsigned int desperation) { return (_wirePacketSendFunction( reinterpret_cast<ZT1_Node *>(this), diff --git a/node/Packet.cpp b/node/Packet.cpp index f4b0dda9..8a2d7c5d 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -50,7 +50,6 @@ const char *Packet::verbString(Verb v) case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH"; case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; - case VERB_PHYSICAL_ADDRESS_CHANGED: return "PHYSICAL_ADDRESS_CHANGED"; } return "(unknown)"; } diff --git a/node/Packet.hpp b/node/Packet.hpp index 78231aac..7439dddc 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -717,45 +717,7 @@ public: * <[6] multicast group MAC> * <[4] 32-bit multicast group ADI> */ - VERB_MULTICAST_FRAME = 14, - - /* Message sent to notify of a change in underlying address: - * <[1] flags> - * <[1] address type> - * <[2] 16-bit length of address> - * <[...] new address> - * - * Flags: - * 0x01 - Address was confirmed (if unset no confirmation was done) - * - * Address types: - * 0x01 - IPv4/UDP - * 0x02 - IPv6/UDP - * 0x03 - IPv4/TCP - * 0x04 - IPv6/TCP - * 0x05 - Ethernet MAC (raw framing address) - * 0x06 - Bluetooth MAC - * 0x07 - HTTP URL - * (other values are reserved) - * - * Address formats: - * IPv4: 32-bit address, 16-bit port in network byte order - * IPv6: 128-bit address, 16-bit port in network byte order - * Ethernet: 48-bit / 6-byte MAC - * Bluetooth: 48-bit / 6-byte Bluetooth MAC - * HTTP URL: ASCII string containing endpoint URL - * - * This should be sent by peers when a new remote address is detected by - * way of a new packet from a previously unknown underlying physical - * address. It may also be sent with flag 0x01 set once a new address is - * confirmed via a bi-directional transaction, indicating a higher - * confidence level. - * - * Peers can use this message to trigger reconnection semantics when - * mobility, DHCP reassignment, VM migration, or other factors lead to - * a change in physical address. - */ - VERB_PHYSICAL_ADDRESS_CHANGED = 15 + VERB_MULTICAST_FRAME = 14 }; /** diff --git a/node/Path.hpp b/node/Path.hpp index 1adb8f99..a5ee6aa9 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -106,7 +106,7 @@ public: * @param t Time of receive * @param d Link desperation of receive */ - inline void received(uint64_t t,int d) throw() { _lastReceived = t; _lastReceiveDesperation = d; } + inline void received(uint64_t t,unsigned int d) throw() { _lastReceived = t; _lastReceiveDesperation = d; } /** * @return Is this a fixed path? @@ -131,10 +131,10 @@ public: * @param now Current time * @return Path desperation, starting at 0 */ - inline int desperation(uint64_t now) const + inline unsigned int desperation(uint64_t now) const { if ((_fixed)&&(_lastSend > _lastReceived)) - return std::max(_lastReceiveDesperation,(int)((_lastSend - _lastReceived) / ZT_DESPERATION_INCREMENT)); + return std::max(_lastReceiveDesperation,(unsigned int)((_lastSend - _lastReceived) / ZT_DESPERATION_INCREMENT)); return _lastReceiveDesperation; } @@ -194,7 +194,7 @@ private: uint64_t _lastSend; uint64_t _lastReceived; InetAddress _addr; - int _lastReceiveDesperation; + unsigned int _lastReceiveDesperation; bool _fixed; }; diff --git a/node/Peer.hpp b/node/Peer.hpp index 9774ecad..fce725b2 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -137,7 +137,7 @@ public: * @param now Current time * @return Best path or NULL if there are no active (or fixed) direct paths */ - Path *getBestPath(uint64_t now) + inline Path *getBestPath(uint64_t now) { Path *bestPath = (Path *)0; uint64_t lrMax = 0; @@ -151,6 +151,25 @@ public: } /** + * Send via best path + * + * @param RR Runtime environment + * @param data Packet data + * @param len Packet length + * @param now Current time + * @return Path used on success or NULL on failure + */ + inline Path *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) + { + Path *bestPath = getBestPath(now); + if (bestPath) { + if (bestPath->send(RR,data,len,now)) + return bestPath; + } + return (Path *)0; + } + + /** * @return All known direct paths to this peer */ std::vector<Path> paths() const diff --git a/node/Switch.cpp b/node/Switch.cpp index fe8282ed..8f1fed66 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -36,16 +36,15 @@ #include "../include/ZeroTierOne.h" #include "Constants.hpp" +#include "RuntimeEnvironment.hpp" #include "Switch.hpp" #include "Node.hpp" -#include "EthernetTap.hpp" #include "InetAddress.hpp" #include "Topology.hpp" -#include "RuntimeEnvironment.hpp" #include "Peer.hpp" -#include "NodeConfig.hpp" #include "CMWC4096.hpp" #include "AntiRecursion.hpp" +#include "Packet.hpp" namespace ZeroTier { @@ -93,13 +92,13 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c * still happen because Windows likes to send broadcasts over interfaces that have little * to do with their intended target audience. :P */ if (!RR->antiRec->checkEthernetFrame(data.data(),data.size())) { - TRACE("%s: rejected recursively addressed ZeroTier packet by tail match (type %s, length: %u)",network->tapDeviceName().c_str(),etherTypeName(etherType),data.size()); + TRACE("%.16llx: rejected recursively addressed ZeroTier packet by tail match (type %s, length: %u)",network->id(),etherTypeName(etherType),data.size()); return; } // Check to make sure this protocol is allowed on this network if (!nconf->permitsEtherType(etherType)) { - TRACE("%s: ignored tap: %s -> %s: ethertype %s not allowed on network %.16llx",network->tapDeviceName().c_str(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),(unsigned long long)network->id()); + TRACE("%.16llx: ignored tap: %s -> %s: ethertype %s not allowed on network %.16llx",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),(unsigned long long)network->id()); return; } @@ -107,7 +106,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c bool fromBridged = false; if (from != network->mac()) { if (!network->permitsBridging(RR->identity.address())) { - LOG("%s: %s -> %s %s not forwarded, bridging disabled on %.16llx or this peer not a bridge",network->tapDeviceName().c_str(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),network->id()); + LOG("%.16llx: %s -> %s %s not forwarded, bridging disabled or this peer not a bridge",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } fromBridged = true; @@ -126,7 +125,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c mg = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(data.field(24,4),4,0)); } else if (!nconf->enableBroadcast()) { // Don't transmit broadcasts if this network doesn't want them - TRACE("%s: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled on network %.16llx",network->tapDeviceName().c_str(),network->id()); + TRACE("%.16llx: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled",network->id()); return; } } @@ -140,11 +139,11 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c // Check multicast/broadcast bandwidth quotas and reject if quota exceeded if (!network->updateAndCheckMulticastBalance(mg,data.size())) { - TRACE("%s: didn't multicast %d bytes, quota exceeded for multicast group %s",network->tapDeviceName().c_str(),(int)data.size(),mg.toString().c_str()); + TRACE("%.16llx: didn't multicast %d bytes, quota exceeded for multicast group %s",network->id(),(int)data.size(),mg.toString().c_str()); return; } - TRACE("%s: MULTICAST %s -> %s %s %d",network->tapDeviceName().c_str(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),(int)data.size()); + TRACE("%.16llx: MULTICAST %s -> %s %s %d",network->id(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),(int)data.size()); RR->mc->send( ((!nconf->isPublic())&&(nconf->com())) ? &(nconf->com()) : (const CertificateOfMembership *)0, @@ -195,7 +194,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c send(outp,true); } } else { - TRACE("%s: UNICAST: %s -> %s %s dropped, destination not a member of closed network %.16llx",network->tapDeviceName().c_str(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),network->id()); + TRACE("%.16llx: UNICAST: %s -> %s %s dropped, destination not a member of private network",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); } return; @@ -368,26 +367,32 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force) return true; } -void Switch::contact(const SharedPtr<Peer> &peer,const InetAddress &atAddr) +void Switch::contact(const SharedPtr<Peer> &peer,const InetAddress &atAddr,unsigned int maxDesperation) { - // Send simple packet directly to indicated address -- works for most NATs - sendHELLO(peer,atAddr); TRACE("sending NAT-t message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); + uint64_t now = RR->node->now(); + + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); + outp.armor(peer->key(),false); + + /* Note that we don't log this as a "sent" packet or send it via the peer's + * normal send() path. That's because this is a trial packet to an + * unconfirmed address. + * + * First attempt is always at desperation zero. Then we escalate to max + * before escalating through other NAT-t strategies. */ + RR->node->putPacket(atAddr,outp.data(),outp.size(),0); + // If we have not punched through after this timeout, open refreshing can of whupass { Mutex::Lock _l(_contactQueue_m); - _contactQueue.push_back(ContactQueueEntry(peer,Utils::now() + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,atAddr)); + _contactQueue.push_back(ContactQueueEntry(peer,now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,atAddr,maxDesperation)); } - - // Kick main loop out of wait so that it can pick up this - // change to our scheduled timer tasks. - RR->sm->whack(); } void Switch::requestWhois(const Address &addr) { - //TRACE("requesting WHOIS for %s",addr.toString().c_str()); bool inserted = false; { Mutex::Lock _l(_outstandingWhoisRequests_m); @@ -436,38 +441,84 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr<Peer> &peer) unsigned long Switch::doTimerTasks() { unsigned long nextDelay = ~((unsigned long)0); // big number, caller will cap return value - uint64_t now = Utils::now(); + const uint64_t now = RR->node->now(); - { + { // Aggressive NAT traversal time! Mutex::Lock _l(_contactQueue_m); for(std::list<ContactQueueEntry>::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) { if (now >= qi->fireAtTime) { - if (!qi->peer->hasActiveDirectPath(now)) { - TRACE("deploying aggressive NAT-t against %s(%s)",qi->peer->address().toString().c_str(),qi->inaddr.toString().c_str()); - - /* Shotgun approach -- literally -- against symmetric NATs. Most of these - * either increment or decrement ports so this gets a good number. Also try - * the original port one more time for good measure, since sometimes it - * fails first time around. */ - int p = (int)qi->inaddr.port() - 2; - for(int k=0;k<6;++k) { - if ((p > 0)&&(p <= 0xffff)) { - qi->inaddr.setPort((unsigned int)p); - sendHELLO(qi->peer,qi->inaddr); - } - ++p; + if (qi->peer->hasActiveDirectPath(now)) { + // We've successfully NAT-t'd, so cancel attempt + _contactQueue.erase(qi++); + continue; + } else { + // Nope, nothing yet. Time to kill some kittens. + + Packet outp(qi->peer->address(),RR->identity.address(),Packet::VERB_NOP); + outp.armor(qi->peer->key(),false); + + switch(qi->strategyIteration) { + case 0: + // First strategy: rifle method: direct packet to known port + ++qi->strategyIteration; + RR->node->putPacket(qi->inaddr,outp.data(),outp.size(),qi->currentDesperation); + break; + case 1: { + // Second strategy: shotgun method up: try a few ports above + ++qi->strategyIteration; + int p = (int)qi->inaddr.port(); + for(int i=0;i<6;++i) { + if (++p > 0xffff) + break; + InetAddress tmpaddr(qi->inaddr); + tmpaddr.setPort((unsigned int)p); + RR->node->putPacket(tmpaddr,outp.data(),outp.size(),qi->currentDesperation); + } + } break; + case 2: { + // Third strategy: shotgun method down: try a few ports below + ++qi->strategyIteration; + int p = (int)qi->inaddr.port(); + for(int i=0;i<3;++i) { + if (--p < 1024) + break; + InetAddress tmpaddr(qi->inaddr); + tmpaddr.setPort((unsigned int)p); + RR->node->putPacket(tmpaddr,outp.data(),outp.size(),qi->currentDesperation); + } + } break; + case 3: + // Fourth strategy: sawed-off shotgun: try random non-privileged ports + for(int i=0;i<16;++i) { + InetAddress tmpaddr(qi->inaddr); + tmpaddr.setPort((unsigned int)(1024 + (RR->prng->next32() % (65536 - 1024)))); + RR->node->putPacket(tmpaddr,outp.data(),outp.size(),qi->currentDesperation); + } + + // Escalate link desperation after all strategies attempted + ++qi->currentDesperation; + if (qi->currentDesperation > qi->maxDesperation) { + // We've tried all strategies at all levels of desperation, give up. + _contactQueue.erase(qi++); + continue; + } else { + // Otherwise restart at new link desperation level (e.g. try a tougher transport) + qi->strategyIteration = 0; + } + break; } - } - _contactQueue.erase(qi++); + qi->fireAtTime = now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY; + nextDelay = std::min(nextDelay,(unsigned long)ZT_NAT_T_TACTICAL_ESCALATION_DELAY); + } } else { nextDelay = std::min(nextDelay,(unsigned long)(qi->fireAtTime - now)); - ++qi; } + ++qi; // if qi was erased, loop will have continued before here } } - { + { // Retry outstanding WHOIS requests Mutex::Lock _l(_outstandingWhoisRequests_m); for(std::map< Address,WhoisRequest >::iterator i(_outstandingWhoisRequests.begin());i!=_outstandingWhoisRequests.end();) { unsigned long since = (unsigned long)(now - i->second.lastSent); @@ -483,12 +534,14 @@ unsigned long Switch::doTimerTasks() TRACE("WHOIS %s (retry %u)",i->first.toString().c_str(),i->second.retries); nextDelay = std::min(nextDelay,(unsigned long)ZT_WHOIS_RETRY_DELAY); } - } else nextDelay = std::min(nextDelay,ZT_WHOIS_RETRY_DELAY - since); + } else { + nextDelay = std::min(nextDelay,ZT_WHOIS_RETRY_DELAY - since); + } ++i; } } - { + { // Time out TX queue packets that never got WHOIS lookups or other info. Mutex::Lock _l(_txQueue_m); for(std::multimap< Address,TXQueueEntry >::iterator i(_txQueue.begin());i!=_txQueue.end();) { if (_trySend(i->second.packet,i->second.encrypt)) @@ -500,7 +553,7 @@ unsigned long Switch::doTimerTasks() } } - { + { // Time out RX queue packets that never got WHOIS lookups or other info. Mutex::Lock _l(_rxQueue_m); for(std::list< SharedPtr<IncomingPacket> >::iterator i(_rxQueue.begin());i!=_rxQueue.end();) { if ((now - (*i)->receiveTime()) > ZT_RECEIVE_QUEUE_TIMEOUT) { @@ -510,7 +563,7 @@ unsigned long Switch::doTimerTasks() } } - { + { // Time out packets that didn't get all their fragments. Mutex::Lock _l(_defragQueue_m); for(std::map< uint64_t,DefragQueueEntry >::iterator i(_defragQueue.begin());i!=_defragQueue.end();) { if ((now - i->second.creationTime) > ZT_FRAGMENTED_PACKET_RECEIVE_TIMEOUT) { @@ -552,11 +605,11 @@ void Switch::_handleRemotePacketFragment(const InetAddress &fromAddr,int linkDes // Note: we don't bother initiating NAT-t for fragments, since heads will set that off. // It wouldn't hurt anything, just redundant and unnecessary. SharedPtr<Peer> relayTo = RR->topology->getPeer(destination); - if ((!relayTo)||(relayTo->send(RR,fragment.data(),fragment.size(),Utils::now()) == Path::PATH_TYPE_NULL)) { + if ((!relayTo)||(!relayTo->send(RR,fragment.data(),fragment.size(),RR->node->now()))) { // Don't know peer or no direct path -- so relay via supernode relayTo = RR->topology->getBestSupernode(); if (relayTo) - relayTo->send(RR,fragment.data(),fragment.size(),Utils::now()); + relayTo->send(RR,fragment.data(),fragment.size(),RR->node->now()); } } else { TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str()); @@ -613,7 +666,7 @@ void Switch::_handleRemotePacketFragment(const InetAddress &fromAddr,int linkDes void Switch::_handleRemotePacketHead(const InetAddress &fromAddr,int linkDesperation,const Buffer<4096> &data) { - SharedPtr<IncomingPacket> packet(new IncomingPacket(data,fromSock,fromAddr)); + SharedPtr<IncomingPacket> packet(new IncomingPacket(data,fromAddr,linkDesperation)); Address source(packet->source()); Address destination(packet->destination()); @@ -626,18 +679,13 @@ void Switch::_handleRemotePacketHead(const InetAddress &fromAddr,int linkDespera packet->incrementHops(); SharedPtr<Peer> relayTo = RR->topology->getPeer(destination); - Path::Type relayedVia; - if ((relayTo)&&((relayedVia = relayTo->send(RR,packet->data(),packet->size(),Utils::now())) != Path::PATH_TYPE_NULL)) { - /* If both paths are UDP, attempt to invoke UDP NAT-t between peers - * by sending VERB_RENDEZVOUS. Do not do this for TCP due to GitHub - * issue #63. */ - if ((fromSock->udp())&&(relayedVia == Path::PATH_TYPE_UDP)) - unite(source,destination,false); + if ((relayTo)&&((relayTo->send(RR,packet->data(),packet->size(),RR->node->now())))) { + unite(source,destination,false); } else { // Don't know peer or no direct path -- so relay via supernode relayTo = RR->topology->getBestSupernode(&source,1,true); if (relayTo) - relayTo->send(RR,packet->data(),packet->size(),Utils::now()); + relayTo->send(RR,packet->data(),packet->size(),RR->node->now()); } } else { TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet->source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str()); @@ -693,15 +741,12 @@ void Switch::_handleBeacon(const InetAddress &fromAddr,int linkDesperation,const return; SharedPtr<Peer> peer(RR->topology->getPeer(beaconAddr)); if (peer) { - uint64_t now = Utils::now(); - if (peer->haveUdpPath(fromAddr)) { - if ((now - peer->lastDirectReceive()) >= ZT_PEER_DIRECT_PING_DELAY) - peer->sendPing(RR,now); - } else { - if ((now - _lastBeacon) < ZT_MIN_BEACON_RESPONSE_INTERVAL) - return; + const uint64_t now = RR->node->now(); + if ((now - _lastBeacon) >= ZT_MIN_BEACON_RESPONSE_INTERVAL) { _lastBeacon = now; - sendHELLO(peer,fromAddr); + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); + outp.armor(peer->key(),false); + RR->node->putPacket(fromAddr,outp.data(),outp.size(),linkDesperation); } } } @@ -713,8 +758,7 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread Packet outp(supernode->address(),RR->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); outp.armor(supernode->key(),true); - uint64_t now = Utils::now(); - if (supernode->send(RR,outp.data(),outp.size(),now) != Path::PATH_TYPE_NULL) + if (supernode->send(RR,outp.data(),outp.size(),RR->node->now())) return supernode->address(); } return Address(); @@ -725,14 +769,15 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) SharedPtr<Peer> peer(RR->topology->getPeer(packet.destination())); if (peer) { - uint64_t now = Utils::now(); + const uint64_t now = RR->node->now(); SharedPtr<Peer> via; - if (peer->hasActiveDirectPath(now)) { + Path *viaPath; + if ((viaPath = peer->getBestPath(now))) { via = peer; } else { via = RR->topology->getBestSupernode(); - if (!via) + if (!(via)||(!(viaPath = via->getBestPath(now)))) return false; } @@ -743,7 +788,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) tmp.armor(peer->key(),encrypt); - if (via->send(RR,tmp.data(),chunkSize,now) != Path::PATH_TYPE_NULL) { + if (viaPath->send(RR,tmp.data(),chunkSize,now)) { if (chunkSize < tmp.size()) { // Too big for one bite, fragment the rest unsigned int fragStart = chunkSize; @@ -756,7 +801,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) for(unsigned int fno=1;fno<totalFragments;++fno) { chunkSize = std::min(remaining,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)); Packet::Fragment frag(tmp,fragStart,chunkSize,fno,totalFragments); - via->send(RR,frag.data(),frag.size(),now); + viaPath->send(RR,frag.data(),frag.size(),now); fragStart += chunkSize; remaining -= chunkSize; } diff --git a/node/Switch.hpp b/node/Switch.hpp index d5d1335f..965636a7 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -134,8 +134,9 @@ public: * * @param peer Peer to contact * @param atAddr Address of peer + * @param linkDesperation Attempt up to given max desperation */ - void contact(const SharedPtr<Peer> &peer,const InetAddress &atAddr); + void contact(const SharedPtr<Peer> &peer,const InetAddress &atAddr,unsigned int maxDesperation); /** * Request WHOIS on a given address @@ -241,14 +242,20 @@ private: struct ContactQueueEntry { ContactQueueEntry() {} - ContactQueueEntry(const SharedPtr<Peer> &p,uint64_t ft,const InetAddress &a) : + ContactQueueEntry(const SharedPtr<Peer> &p,uint64_t ft,const InetAddress &a,unsigned int md) : peer(p), fireAtTime(ft), - inaddr(a) {} + inaddr(a), + maxDesperation(md), + currentDesperation(0), + strategyIteration(1) {} // start with 2nd strategy, zero desperation, since we've already tried 0/0 SharedPtr<Peer> peer; uint64_t fireAtTime; InetAddress inaddr; + unsigned int maxDesperation; + unsigned int currentDesperation; + unsigned int strategyIteration; }; std::list<ContactQueueEntry> _contactQueue; Mutex _contactQueue_m; |