diff options
Diffstat (limited to 'node/Peer.hpp')
-rw-r--r-- | node/Peer.hpp | 192 |
1 files changed, 101 insertions, 91 deletions
diff --git a/node/Peer.hpp b/node/Peer.hpp index de5df08f..5766a27b 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -48,6 +48,9 @@ #include "NonCopyable.hpp" #include "Mutex.hpp" +// Increment if serialization has changed +#define ZT_PEER_SERIALIZATION_VERSION 5 + namespace ZeroTier { /** @@ -104,28 +107,37 @@ public: /** * Must be called on authenticated packet receive from this peer * - * This must be called only after a packet has passed authentication - * checking. Packets that fail are silently discarded. - * * @param _r Runtime environment * @param localPort Local port on which packet was received * @param remoteAddr Internet address of sender * @param hops ZeroTier (not IP) hops + * @param packetId Packet ID * @param verb Packet verb + * @param inRePacketId Packet ID in reply to (for OK/ERROR, 0 otherwise) + * @param inReVerb Verb in reply to (for OK/ERROR, VERB_NOP otherwise) * @param now Current time */ - void onReceive(const RuntimeEnvironment *_r,Demarc::Port localPort,const InetAddress &remoteAddr,unsigned int hops,Packet::Verb verb,uint64_t now); + void onReceive( + const RuntimeEnvironment *_r, + Demarc::Port localPort, + const InetAddress &remoteAddr, + unsigned int hops, + uint64_t packetId, + Packet::Verb verb, + uint64_t inRePacketId, + Packet::Verb inReVerb, + uint64_t now); /** - * Send a packet to this peer + * Send a UDP packet to this peer * * @param _r Runtime environment * @param data Data to send * @param len Length of packet * @param now Current time - * @return True if packet appears to have been sent, false on local failure + * @return NULL_PORT or port packet was sent from */ - bool send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now); + Demarc::Port send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now); /** * Send firewall opener to active link @@ -226,68 +238,29 @@ public: /** * @return Lowest of measured latencies of all paths or 0 if unknown */ - inline unsigned int latency() const - throw() - { - if (_ipv4p.latency) { - if (_ipv6p.latency) - return std::min(_ipv4p.latency,_ipv6p.latency); - else return _ipv4p.latency; - } else if (_ipv6p.latency) - return _ipv6p.latency; - return 0; - } - - /** - * @param addr Remote address - * @param latency Latency measurment - */ - inline void setLatency(const InetAddress &addr,unsigned int latency) - { - if (addr == _ipv4p.addr) { - _ipv4p.latency = latency; - } else if (addr == _ipv6p.addr) { - _ipv6p.latency = latency; - } - } + inline unsigned int latency() const throw() { return _latency; } /** * @return True if this peer has at least one direct IP address path */ - inline bool hasDirectPath() const - throw() - { - return ((_ipv4p.addr)||(_ipv6p.addr)); - } + inline bool hasDirectPath() const throw() { return ((_ipv4p.addr)||(_ipv6p.addr)); } /** * @return True if this peer has at least one direct IP address path that looks active * * @param now Current time */ - inline bool hasActiveDirectPath(uint64_t now) const - throw() - { - return ((_ipv4p.isActive(now))||(_ipv6p.isActive(now))); - } + inline bool hasActiveDirectPath(uint64_t now) const throw() { return ((_ipv4p.isActive(now))||(_ipv6p.isActive(now))); } /** * @return IPv4 direct address or null InetAddress if none */ - inline InetAddress ipv4Path() const - throw() - { - return _ipv4p.addr; - } + inline InetAddress ipv4Path() const throw() { return _ipv4p.addr; } /** * @return IPv6 direct address or null InetAddress if none */ - inline InetAddress ipv6Path() const - throw() - { - return _ipv4p.addr; - } + inline InetAddress ipv6Path() const throw() { return _ipv4p.addr; } /** * @return IPv4 direct address or null InetAddress if none @@ -312,13 +285,9 @@ public: } /** - * @return 256-bit encryption key + * @return 256-bit secret symmetric encryption key */ - inline const unsigned char *key() const - throw() - { - return _key; - } + inline const unsigned char *key() const throw() { return _key; } /** * Set the remote version of the peer (not persisted) @@ -347,10 +316,55 @@ public: return std::string("?"); } + /** + * Called when certain packet types are sent that expect OK responses + * + * @param packetId ID of sent packet + * @param verb Verb of sent packet + * @param sentFromLocalPort Outgoing local port + * @param now Current time + */ + inline void expectResponseTo(uint64_t packetId,Packet::Verb verb,Demarc::Port sentFromLocalPort,uint64_t now) + throw() + { + unsigned int p = _requestHistoryPtr++ % ZT_PEER_REQUEST_HISTORY_LENGTH; + _requestHistory[p].timestamp = now; + _requestHistory[p].packetId = packetId; + _requestHistory[p].localPort = sentFromLocalPort; + _requestHistory[p].verb = verb; + } + + /** + * @return True if this Peer is initialized with something + */ + inline operator bool() const throw() { return (_id); } + + /** + * Find a common set of addresses by which two peers can link, if any + * + * @param a Peer A + * @param b Peer B + * @param now Current time + * @return Pair: B's address to send to A, A's address to send to B + */ + static inline std::pair<InetAddress,InetAddress> findCommonGround(const Peer &a,const Peer &b,uint64_t now) + throw() + { + if ((a._ipv6p.isActive(now))&&(b._ipv6p.isActive(now))) + return std::pair<InetAddress,InetAddress>(b._ipv6p.addr,a._ipv6p.addr); + else if ((a._ipv4p.isActive(now))&&(b._ipv4p.isActive(now))) + return std::pair<InetAddress,InetAddress>(b._ipv4p.addr,a._ipv4p.addr); + else if ((a._ipv6p.addr)&&(b._ipv6p.addr)) + return std::pair<InetAddress,InetAddress>(b._ipv6p.addr,a._ipv6p.addr); + else if ((a._ipv4p.addr)&&(b._ipv4p.addr)) + return std::pair<InetAddress,InetAddress>(b._ipv4p.addr,a._ipv4p.addr); + return std::pair<InetAddress,InetAddress>(); + } + template<unsigned int C> inline void serialize(Buffer<C> &b) { - b.append((unsigned char)4); // version + b.append((unsigned char)ZT_PEER_SERIALIZATION_VERSION); b.append(_key,sizeof(_key)); _id.serialize(b,false); _ipv4p.serialize(b); @@ -362,14 +376,14 @@ public: b.append((uint16_t)_vMajor); b.append((uint16_t)_vMinor); b.append((uint16_t)_vRevision); + b.append((uint16_t)_latency); } - template<unsigned int C> inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0) { unsigned int p = startAt; - if (b[p++] != 4) + if (b[p++] != ZT_PEER_SERIALIZATION_VERSION) throw std::invalid_argument("Peer: deserialize(): version mismatch"); memcpy(_key,b.field(p,sizeof(_key)),sizeof(_key)); p += sizeof(_key); @@ -383,38 +397,14 @@ public: _vMajor = b.template at<uint16_t>(p); p += sizeof(uint16_t); _vMinor = b.template at<uint16_t>(p); p += sizeof(uint16_t); _vRevision = b.template at<uint16_t>(p); p += sizeof(uint16_t); + _latency = b.template at<uint16_t>(p); p += sizeof(uint16_t); return (p - startAt); } - - /** - * @return True if this Peer is initialized with something - */ - inline operator bool() const throw() { return (_id); } - +private: /** - * Find a common set of addresses by which two peers can link, if any - * - * @param a Peer A - * @param b Peer B - * @param now Current time - * @return Pair: B's address to send to A, A's address to send to B + * A direct IP path to a peer */ - static inline std::pair<InetAddress,InetAddress> findCommonGround(const Peer &a,const Peer &b,uint64_t now) - throw() - { - if ((a._ipv6p.isActive(now))&&(b._ipv6p.isActive(now))) - return std::pair<InetAddress,InetAddress>(b._ipv6p.addr,a._ipv6p.addr); - else if ((a._ipv4p.isActive(now))&&(b._ipv4p.isActive(now))) - return std::pair<InetAddress,InetAddress>(b._ipv4p.addr,a._ipv4p.addr); - else if ((a._ipv6p.addr)&&(b._ipv6p.addr)) - return std::pair<InetAddress,InetAddress>(b._ipv6p.addr,a._ipv6p.addr); - else if ((a._ipv4p.addr)&&(b._ipv4p.addr)) - return std::pair<InetAddress,InetAddress>(b._ipv4p.addr,a._ipv4p.addr); - return std::pair<InetAddress,InetAddress>(); - } - -private: class WanPath { public: @@ -423,7 +413,6 @@ private: lastReceive(0), lastFirewallOpener(0), localPort(Demarc::ANY_PORT), - latency(0), addr(), fixed(false) { @@ -443,7 +432,6 @@ private: b.append(lastReceive); b.append(lastFirewallOpener); b.append(Demarc::portToInt(localPort)); - b.append((uint16_t)latency); b.append((unsigned char)addr.type()); switch(addr.type()) { @@ -472,7 +460,6 @@ private: lastReceive = b.template at<uint64_t>(p); p += sizeof(uint64_t); lastFirewallOpener = b.template at<uint64_t>(p); p += sizeof(uint64_t); localPort = Demarc::intToPort(b.template at<uint64_t>(p)); p += sizeof(uint64_t); - latency = b.template at<uint16_t>(p); p += sizeof(uint16_t); switch ((InetAddress::AddressType)b[p++]) { case InetAddress::TYPE_NULL: @@ -497,11 +484,29 @@ private: uint64_t lastReceive; uint64_t lastFirewallOpener; Demarc::Port localPort; // ANY_PORT if not defined (size: uint64_t) - unsigned int latency; // 0 if never determined InetAddress addr; // null InetAddress if path is undefined bool fixed; // do not learn address from received packets }; + /** + * A history of a packet sent to a peer expecing a response (e.g. HELLO) + */ + class RequestHistoryItem + { + public: + RequestHistoryItem() : + timestamp(0), + packetId(0), + verb(Packet::VERB_NOP) + { + } + + uint64_t timestamp; + uint64_t packetId; + Demarc::Port localPort; + Packet::Verb verb; + }; + unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; Identity _id; @@ -512,8 +517,13 @@ private: uint64_t _lastUnicastFrame; uint64_t _lastMulticastFrame; uint64_t _lastAnnouncedTo; + unsigned int _latency; // milliseconds, 0 if not known unsigned int _vMajor,_vMinor,_vRevision; + // not persisted + RequestHistoryItem _requestHistory[ZT_PEER_REQUEST_HISTORY_LENGTH]; + volatile unsigned int _requestHistoryPtr; + AtomicCounter __refCount; }; |