Browse Source

Some cleanup, docs, and Path -> Path > RemotePath refactor.

Adam Ierymenko 10 years ago
parent
commit
93bb934d4e
9 changed files with 197 additions and 108 deletions
  1. 3 3
      node/Node.cpp
  2. 24 8
      node/Packet.hpp
  3. 113 0
      node/Path.hpp
  4. 10 5
      node/Peer.cpp
  5. 21 15
      node/Peer.hpp
  6. 23 74
      node/RemotePath.hpp
  7. 1 1
      node/SelfAwareness.cpp
  8. 1 1
      node/Switch.cpp
  9. 1 1
      node/Topology.cpp

+ 3 - 3
node/Node.cpp

@@ -388,10 +388,10 @@ ZT1_PeerList *Node::peers() const
 		p->latency = pi->second->latency();
 		p->role = RR->topology->isRoot(pi->second->identity()) ? ZT1_PEER_ROLE_ROOT : ZT1_PEER_ROLE_LEAF;
 
-		std::vector<Path> paths(pi->second->paths());
-		Path *bestPath = pi->second->getBestPath(_now);
+		std::vector<RemotePath> paths(pi->second->paths());
+		RemotePath *bestPath = pi->second->getBestPath(_now);
 		p->pathCount = 0;
-		for(std::vector<Path>::iterator path(paths.begin());path!=paths.end();++path) {
+		for(std::vector<RemotePath>::iterator path(paths.begin());path!=paths.end();++path) {
 			memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage));
 			p->paths[p->pathCount].lastSend = path->lastSend();
 			p->paths[p->pathCount].lastReceive = path->lastReceived();

+ 24 - 8
node/Packet.hpp

@@ -899,16 +899,17 @@ public:
 		 * Path record format:
 		 *   <[1] flags>
 		 *   <[1] metric from 0 (highest priority) to 255 (lowest priority)>
+		 *   <[2] length of extended path characteristics or 0 for none>
+		 *   <[...] extended path characteristics>
 		 *   <[1] address type>
 		 *   <[...] address>
 		 *
 		 * Path record flags:
-		 *   0x01 - Blacklist this path, do not use
-		 *   0x02 - Reliable path (no keepalives, etc. necessary)
-		 *   0x04 - Trusted path (encryption and authentication optional)
-		 *
-		 * None of the above flags are implemented yet as of 1.0.4. They're
-		 * reserved for future use.
+		 *   0x01 - Forget this path if it is currently known
+		 *   0x02 - Blacklist this path, do not use
+		 *   0x04 - Reliable path (no NAT keepalives, etc. are necessary)
+		 *   0x08 - Disable encryption (trust: privacy)
+		 *   0x10 - Disable encryption and authentication (trust: ultimate)
 		 *
 		 * Address types and addresses are of the same format as the destination
 		 * address type and address in HELLO.
@@ -916,9 +917,24 @@ public:
 		 * The receiver may, upon receiving a push, attempt to establish a
 		 * direct link to one or more of the indicated addresses. It is the
 		 * responsibility of the sender to limit which peers it pushes direct
-		 * paths to to those with whom it has a trust relationship.
+		 * paths to to those with whom it has a trust relationship. The receiver
+		 * must obey any restrictions provided such as exclusivity or blacklists.
+		 * OK responses to this message are optional.
 		 *
-		 * OK/ERROR are not generated.
+		 * Note that a direct path push does not imply that learned paths can't
+		 * be used unless they are blacklisted explicitly or unless flag 0x01
+		 * is set.
+		 *
+		 * Only a subset of this functionality is currently implemented: basic
+		 * path pushing and learning. Metrics, most flags, and OK responses are
+		 * not yet implemented as of 1.0.4.
+		 *
+		 * OK response payload:
+		 *   <[2] 16-bit number of active direct paths we already have>
+		 *   <[2] 16-bit number of paths in push that we don't already have>
+		 *   <[2] 16-bit number of new paths we are trying (or will try)>
+		 *
+		 * ERROR is presently not sent.
 		 */
 		VERB_PUSH_DIRECT_PATHS = 16
 	};

+ 113 - 0
node/Path.hpp

@@ -0,0 +1,113 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015  ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_PATH_HPP
+#define ZT_PATH_HPP
+
+#include "Constants.hpp"
+#include "InetAddress.hpp"
+#include "Utils.hpp"
+
+namespace ZeroTier {
+
+class Path
+{
+public:
+	enum Trust
+	{
+		TRUST_NORMAL,
+		TRUST_PRIVACY,
+		TRUST_ULTIMATE
+	};
+
+	Path() :
+		_addr(),
+		_metric(0),
+		_trust(TRUST_NORMAL),
+		_reliable(false),
+		_fixed(false)
+	{
+	}
+
+	Path(const InetAddress &addr,int metric,Trust trust,bool reliable,bool fixed) :
+		_addr(addr),
+		_metric(metric),
+		_trust(trust),
+		_reliable(reliable),
+		_fixed(fixed)
+	{
+	}
+
+	/**
+	 * @return Physical address
+	 */
+	inline const InetAddress &address() const throw() { return _addr; }
+
+	/**
+	 * @return Metric (higher == worse) or negative if path is blacklisted
+	 */
+	inline int metric() const throw() { return _metric; }
+
+	/**
+	 * @return Path trust level
+	 */
+	inline Trust trust() const throw() { return _trust; }
+
+	/**
+	 * @return True if path is considered reliable (no NAT keepalives etc. are needed)
+	 */
+	inline bool reliable() const throw() { return _reliable; }
+
+	/**
+	 * @return Is this a fixed path?
+	 */
+	inline bool fixed() const throw() { return _fixed; }
+
+	/**
+	 * @return True if address is non-NULL
+	 */
+	inline operator bool() const throw() { return (_addr); }
+
+	// Comparisons are by address only
+	inline bool operator==(const Path &p) const throw() { return (_addr == p._addr); }
+	inline bool operator!=(const Path &p) const throw() { return (_addr != p._addr); }
+	inline bool operator<(const Path &p) const throw() { return (_addr < p._addr); }
+	inline bool operator>(const Path &p) const throw() { return (_addr > p._addr); }
+	inline bool operator<=(const Path &p) const throw() { return (_addr <= p._addr); }
+	inline bool operator>=(const Path &p) const throw() { return (_addr >= p._addr); }
+
+protected:
+	InetAddress _addr;
+	int _metric; // negative == blacklisted
+	Trust _trust;
+	bool _reliable;
+	bool _fixed;
+};
+
+} // namespace ZeroTier
+
+#endif

+ 10 - 5
node/Peer.cpp

@@ -46,6 +46,7 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
 	_lastMulticastFrame(0),
 	_lastAnnouncedTo(0),
 	_lastPathConfirmationSent(0),
+	_lastDirectPathPush(0),
 	_vMajor(0),
 	_vMinor(0),
 	_vRevision(0),
@@ -86,7 +87,7 @@ void Peer::received(
 			if (!pathIsConfirmed) {
 				if ((verb == Packet::VERB_OK)&&(inReVerb == Packet::VERB_HELLO)) {
 					// Learn paths if they've been confirmed via a HELLO
-					Path *slot = (Path *)0;
+					RemotePath *slot = (RemotePath *)0;
 					if (np < ZT1_MAX_PEER_NETWORK_PATHS) {
 						// Add new path
 						slot = &(_paths[np++]);
@@ -101,7 +102,7 @@ void Peer::received(
 						}
 					}
 					if (slot) {
-						slot->init(remoteAddr,false);
+						*slot = RemotePath(remoteAddr,false);
 						slot->received(now);
 						_numPaths = np;
 						pathIsConfirmed = true;
@@ -193,7 +194,7 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &at
 
 void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
 {
-	Path *const bestPath = getBestPath(now);
+	RemotePath *const bestPath = getBestPath(now);
 	if ((bestPath)&&(bestPath->active(now))) {
 		if ((now - bestPath->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) {
 			TRACE("PING %s(%s)",_id.address().toString().c_str(),bestPath->address().toString().c_str());
@@ -207,7 +208,11 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
 	}
 }
 
-void Peer::addPath(const Path &newp)
+//void Peer::pushDirectPaths(const std::vector<Path> &dps,uint64_t now,bool force)
+//{
+//}
+
+void Peer::addPath(const RemotePath &newp)
 {
 	unsigned int np = _numPaths;
 
@@ -218,7 +223,7 @@ void Peer::addPath(const Path &newp)
 		}
 	}
 
-	Path *slot = (Path *)0;
+	RemotePath *slot = (RemotePath *)0;
 	if (np < ZT1_MAX_PEER_NETWORK_PATHS) {
 		// Add new path
 		slot = &(_paths[np++]);

+ 21 - 15
node/Peer.hpp

@@ -40,7 +40,7 @@
 #include "../include/ZeroTierOne.h"
 
 #include "RuntimeEnvironment.hpp"
-#include "Path.hpp"
+#include "RemotePath.hpp"
 #include "Address.hpp"
 #include "Utils.hpp"
 #include "Identity.hpp"
@@ -53,11 +53,7 @@
 namespace ZeroTier {
 
 /**
- * Peer on P2P Network
- *
- * This struture is not locked, volatile, and memcpy-able. NonCopyable
- * semantics are just there to prevent bugs, not because it isn't safe
- * to copy.
+ * Peer on P2P Network (virtual layer 1)
  */
 class Peer : NonCopyable
 {
@@ -130,9 +126,9 @@ public:
 	 * @param now Current time
 	 * @return Best path or NULL if there are no active (or fixed) direct paths
 	 */
-	inline Path *getBestPath(uint64_t now)
+	inline RemotePath *getBestPath(uint64_t now)
 	{
-		Path *bestPath = (Path *)0;
+		RemotePath *bestPath = (RemotePath *)0;
 		uint64_t lrMax = 0;
 		for(unsigned int p=0,np=_numPaths;p<np;++p) {
 			if ((_paths[p].active(now))&&(_paths[p].lastReceived() >= lrMax)) {
@@ -152,14 +148,14 @@ public:
 	 * @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)
+	inline RemotePath *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
 	{
-		Path *bestPath = getBestPath(now);
+		RemotePath *bestPath = getBestPath(now);
 		if (bestPath) {
 			if (bestPath->send(RR,data,len,now))
 				return bestPath;
 		}
-		return (Path *)0;
+		return (RemotePath *)0;
 	}
 
 	/**
@@ -182,12 +178,21 @@ public:
 	 */
 	void doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now);
 
+	/**
+	 * Push direct paths (if within rate limit)
+	 *
+	 * @param dps Direct paths to me to push to this peer
+	 * @param now Current time
+	 * @param force If true, force regardless of when we pushed direct paths last
+	 */
+	void pushDirectPaths(const std::vector<InetAddress> &dps,uint64_t now,bool force);
+
 	/**
 	 * @return All known direct paths to this peer
 	 */
-	inline std::vector<Path> paths() const
+	inline std::vector<RemotePath> paths() const
 	{
-		std::vector<Path> pp;
+		std::vector<RemotePath> pp;
 		for(unsigned int p=0,np=_numPaths;p<np;++p)
 			pp.push_back(_paths[p]);
 		return pp;
@@ -295,7 +300,7 @@ public:
 	 *
 	 * @param p New path to add
 	 */
-	void addPath(const Path &newp);
+	void addPath(const RemotePath &newp);
 
 	/**
 	 * Clear paths
@@ -412,12 +417,13 @@ private:
 	uint64_t _lastMulticastFrame;
 	uint64_t _lastAnnouncedTo;
 	uint64_t _lastPathConfirmationSent;
+	uint64_t _lastDirectPathPush;
 	uint16_t _vProto;
 	uint16_t _vMajor;
 	uint16_t _vMinor;
 	uint16_t _vRevision;
 	Identity _id;
-	Path _paths[ZT1_MAX_PEER_NETWORK_PATHS];
+	RemotePath _paths[ZT1_MAX_PEER_NETWORK_PATHS];
 	unsigned int _numPaths;
 	unsigned int _latency;
 

+ 23 - 74
node/RemotePath.hpp

@@ -25,72 +25,56 @@
  * LLC. Start here: http://www.zerotier.com/
  */
 
-#ifndef ZT_PATH_HPP
-#define ZT_PATH_HPP
+#ifndef ZT_REMOTEPATH_HPP
+#define ZT_REMOTEPATH_HPP
 
 #include <stdint.h>
 #include <string.h>
 
 #include <stdexcept>
-#include <string>
 #include <algorithm>
 
-#include "Constants.hpp"
+#include "Path.hpp"
 #include "Node.hpp"
-#include "InetAddress.hpp"
-#include "Utils.hpp"
 #include "AntiRecursion.hpp"
 #include "RuntimeEnvironment.hpp"
 
 namespace ZeroTier {
 
 /**
- * WAN address and protocol for reaching a peer
+ * Path to a remote peer
  *
- * This structure is volatile and memcpy-able, and depends on
- * InetAddress being similarly safe.
+ * This extends Path to include status information about path activity.
  */
-class Path
+class RemotePath : public Path
 {
 public:
-	Path() :
-		_addr(),
+	RemotePath() :
+		Path(),
 		_lastSend(0),
-		_lastReceived(0),
-		_fixed(false) {}
+		_lastReceived(0) {}
 
-	Path(const Path &p) throw() { memcpy(this,&p,sizeof(Path)); }
-
-	Path(const InetAddress &addr,bool fixed) :
-		_addr(addr),
+	RemotePath(const InetAddress &addr,bool fixed) :
+		Path(addr,0,TRUST_NORMAL,false,fixed),
 		_lastSend(0),
-		_lastReceived(0),
-		_fixed(fixed) {}
+		_lastReceived(0) {}
 
-	inline void init(const InetAddress &addr,bool fixed)
-	{
-		_addr = addr;
-		_lastSend = 0;
-		_lastReceived = 0;
-		_fixed = fixed;
-	}
+	inline uint64_t lastSend() const throw() { return _lastSend; }
+	inline uint64_t lastReceived() const throw() { return _lastReceived; }
 
-	inline Path &operator=(const Path &p)
+	/**
+	 * @param f New value of parent 'fixed' field
+	 */
+	inline void setFixed(const bool f)
+		throw()
 	{
-		if (this != &p)
-			memcpy(this,&p,sizeof(Path));
-		return *this;
+		_fixed = f;
 	}
 
-	inline const InetAddress &address() const throw() { return _addr; }
-
-	inline uint64_t lastSend() const throw() { return _lastSend; }
-	inline uint64_t lastReceived() const throw() { return _lastReceived; }
-
 	/**
-	 * Called when a packet is sent to this path
+	 * Called when a packet is sent to this remote path
 	 *
-	 * This is called automatically by Path::send().
+	 * This is called automatically by RemotePath::send().
 	 *
 	 * @param t Time of send
 	 */
@@ -101,7 +85,7 @@ public:
 	}
 
 	/**
-	 * Called when a packet is received from this path
+	 * Called when a packet is received from this remote path
 	 *
 	 * @param t Time of receive
 	 */
@@ -111,16 +95,6 @@ public:
 		_lastReceived = t;
 	}
 
-	/**
-	 * @return Is this a fixed path?
-	 */
-	inline bool fixed() const throw() { return _fixed; }
-
-	/**
-	 * @param f New value of fixed path flag
-	 */
-	inline void setFixed(bool f) throw() { _fixed = f; }
-
 	/**
 	 * @param now Current time
 	 * @return True if this path is fixed or has received data in last ACTIVITY_TIMEOUT ms
@@ -150,34 +124,9 @@ public:
 		return false;
 	}
 
-	/**
-	 * @param now Current time
-	 * @return Human-readable address and other information about this path
-	 */
-	inline std::string toString(uint64_t now) const
-	{
-		char tmp[1024];
-		Utils::snprintf(tmp,sizeof(tmp),"%s(%s)",
-			_addr.toString().c_str(),
-			((_fixed) ? "fixed" : (active(now) ? "active" : "inactive"))
-		);
-		return std::string(tmp);
-	}
-
-	inline operator bool() const throw() { return (_addr); }
-
-	inline bool operator==(const Path &p) const throw() { return (_addr == p._addr); }
-	inline bool operator!=(const Path &p) const throw() { return (_addr != p._addr); }
-	inline bool operator<(const Path &p) const throw() { return (_addr < p._addr); }
-	inline bool operator>(const Path &p) const throw() { return (_addr > p._addr); }
-	inline bool operator<=(const Path &p) const throw() { return (_addr <= p._addr); }
-	inline bool operator>=(const Path &p) const throw() { return (_addr >= p._addr); }
-
 private:
-	InetAddress _addr;
 	uint64_t _lastSend;
 	uint64_t _lastReceived;
-	bool _fixed;
 };
 
 } // namespace ZeroTier

+ 1 - 1
node/SelfAwareness.cpp

@@ -120,7 +120,7 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &reporterPhysi
 		// they are still considered alive so that we will re-establish direct links.
 		SharedPtr<Peer> sn(RR->topology->getBestRoot());
 		if (sn) {
-			Path *snp = sn->getBestPath(now);
+			RemotePath *snp = sn->getBestPath(now);
 			if (snp) {
 				for(std::vector< SharedPtr<Peer> >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) {
 					if ((*p)->alive(now)) {

+ 1 - 1
node/Switch.cpp

@@ -733,7 +733,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid)
 	if (peer) {
 		const uint64_t now = RR->node->now();
 
-		Path *viaPath = peer->getBestPath(now);
+		RemotePath *viaPath = peer->getBestPath(now);
 		if (!viaPath) {
 			SharedPtr<Peer> relay;
 

+ 1 - 1
node/Topology.cpp

@@ -62,7 +62,7 @@ void Topology::setRootServers(const std::map< Identity,std::vector<InetAddress>
 			if (!p)
 				p = SharedPtr<Peer>(new Peer(RR->identity,i->first));
 			for(std::vector<InetAddress>::const_iterator j(i->second.begin());j!=i->second.end();++j)
-				p->addPath(Path(*j,true));
+				p->addPath(RemotePath(*j,true));
 			p->use(now);
 			_rootPeers.push_back(p);
 		}