diff options
Diffstat (limited to 'node/Path.hpp')
-rw-r--r-- | node/Path.hpp | 187 |
1 files changed, 142 insertions, 45 deletions
diff --git a/node/Path.hpp b/node/Path.hpp index 0e53772d..00f8ed36 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -28,12 +28,29 @@ #ifndef ZT_PATH_HPP #define ZT_PATH_HPP +#include <stdint.h> +#include <string.h> + +#include <stdexcept> +#include <algorithm> + #include "Constants.hpp" #include "InetAddress.hpp" -#include "Utils.hpp" + +/** + * Flag indicating that this path is suboptimal + * + * This is used in cluster mode to indicate that the peer has been directed + * to a better path. This path can continue to be used but shouldn't be kept + * or advertised to other cluster members. Not used if clustering is not + * built and enabled. + */ +#define ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL 0x0001 namespace ZeroTier { +class RuntimeEnvironment; + /** * Base class for paths * @@ -42,43 +59,84 @@ namespace ZeroTier { class Path { public: + Path() : + _lastSend(0), + _lastReceived(0), + _addr(), + _localAddress(), + _flags(0), + _ipScope(InetAddress::IP_SCOPE_NONE) + { + } + + Path(const InetAddress &localAddress,const InetAddress &addr) : + _lastSend(0), + _lastReceived(0), + _addr(addr), + _localAddress(localAddress), + _flags(0), + _ipScope(addr.ipScope()) + { + } + + inline Path &operator=(const Path &p) + { + if (this != &p) + memcpy(this,&p,sizeof(Path)); + return *this; + } + /** - * Path trust category + * Called when a packet is sent to this remote path * - * Note that this is NOT peer trust and has nothing to do with root server - * designations or other trust metrics. This indicates how much we trust - * this path to be secure and/or private. A trust level of normal means - * encrypt and authenticate all traffic. Privacy trust means we can send - * traffic in the clear. Ultimate trust means we don't even need - * authentication. Generally a private path would be a hard-wired local - * LAN, while an ultimate trust path would be a physically isolated private - * server backplane. + * This is called automatically by Path::send(). * - * Nearly all paths will be normal trust. The other levels are for high - * performance local SDN use only. + * @param t Time of send + */ + inline void sent(uint64_t t) { _lastSend = t; } + + /** + * Called when a packet is received from this remote path * - * These values MUST match ZT1_LocalInterfaceAddressTrust in ZeroTierOne.h + * @param t Time of receive */ - enum Trust - { - TRUST_NORMAL = 0, - TRUST_PRIVACY = 1, - TRUST_ULTIMATE = 2 - }; + inline void received(uint64_t t) { _lastReceived = t; } - Path() : - _addr(), - _ipScope(InetAddress::IP_SCOPE_NONE), - _trust(TRUST_NORMAL) + /** + * @param now Current time + * @return True if this path appears active + */ + inline bool active(uint64_t now) const + throw() { + return ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT); } - Path(const InetAddress &addr,int metric,Trust trust) : - _addr(addr), - _ipScope(addr.ipScope()), - _trust(trust) - { - } + /** + * Send a packet via this path + * + * @param RR Runtime environment + * @param data Packet data + * @param len Packet length + * @param now Current time + * @return True if transport reported success + */ + bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now); + + /** + * @return Address of local side of this path or NULL if unspecified + */ + inline const InetAddress &localAddress() const throw() { return _localAddress; } + + /** + * @return Time of last send to this path + */ + inline uint64_t lastSend() const throw() { return _lastSend; } + + /** + * @return Time of last receive from this path + */ + inline uint64_t lastReceived() const throw() { return _lastReceived; } /** * @return Physical address @@ -93,19 +151,25 @@ public: /** * @return Preference rank, higher == better */ - inline int preferenceRank() const throw() { return (int)_ipScope; } // IP scopes are in ascending rank order in InetAddress.hpp - - /** - * @return Path trust level - */ - inline Trust trust() const throw() { return _trust; } + inline int preferenceRank() const throw() + { + // First, since the scope enum values in InetAddress.hpp are in order of + // use preference rank, we take that. Then we multiple by two, yielding + // a sequence like 0, 2, 4, 6, etc. Then if it's IPv6 we add one. This + // makes IPv6 addresses of a given scope outrank IPv4 addresses of the + // same scope -- e.g. 1 outranks 0. This makes us prefer IPv6, but not + // if the address scope/class is of a fundamentally lower rank. + return ( ((int)_ipScope * 2) + ((_addr.ss_family == AF_INET6) ? 1 : 0) ); + } /** * @return True if path is considered reliable (no NAT keepalives etc. are needed) */ inline bool reliable() const throw() { - return ((_ipScope != InetAddress::IP_SCOPE_GLOBAL)&&(_ipScope != InetAddress::IP_SCOPE_PSEUDOPRIVATE)); + if (_addr.ss_family == AF_INET) + return ((_ipScope != InetAddress::IP_SCOPE_GLOBAL)&&(_ipScope != InetAddress::IP_SCOPE_PSEUDOPRIVATE)); + return true; } /** @@ -113,14 +177,6 @@ public: */ 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); } - /** * Check whether this address is valid for a ZeroTier path * @@ -154,10 +210,51 @@ public: return false; } +#ifdef ZT_ENABLE_CLUSTER + /** + * @param f New value of ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL + */ + inline void setClusterSuboptimal(bool f) { _flags = ((f) ? (_flags | ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL) : (_flags & (~ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL))); } + + /** + * @return True if ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL is set + */ + inline bool isClusterSuboptimal() const { return ((_flags & ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL) != 0); } +#endif + + template<unsigned int C> + inline void serialize(Buffer<C> &b) const + { + b.append((uint8_t)0); // version + b.append((uint64_t)_lastSend); + b.append((uint64_t)_lastReceived); + _addr.serialize(b); + _localAddress.serialize(b); + b.append((uint16_t)_flags); + } + + template<unsigned int C> + inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0) + { + unsigned int p = startAt; + if (b[p++] != 0) + throw std::invalid_argument("invalid serialized Path"); + _lastSend = b.template at<uint64_t>(p); p += 8; + _lastReceived = b.template at<uint64_t>(p); p += 8; + p += _addr.deserialize(b,p); + p += _localAddress.deserialize(b,p); + _flags = b.template at<uint16_t>(p); p += 2; + _ipScope = _addr.ipScope(); + return (p - startAt); + } + private: + uint64_t _lastSend; + uint64_t _lastReceived; InetAddress _addr; + InetAddress _localAddress; + unsigned int _flags; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often - Trust _trust; }; } // namespace ZeroTier |