소스 검색

Sane-ify Address, get rid of goofy union thingy.

Adam Ierymenko 12 년 전
부모
커밋
9cf734b74a
6개의 변경된 파일134개의 추가작업 그리고 69개의 파일을 삭제
  1. 109 55
      node/Address.hpp
  2. 6 2
      node/Identity.cpp
  3. 1 1
      node/Identity.hpp
  4. 4 4
      node/Pack.cpp
  5. 4 4
      node/Switch.cpp
  6. 10 3
      node/Topology.cpp

+ 109 - 55
node/Address.hpp

@@ -28,70 +28,131 @@
 #ifndef _ZT_ADDRESS_HPP
 #define _ZT_ADDRESS_HPP
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <stdint.h>
+#include <string.h>
 #include <string>
 #include "Utils.hpp"
 #include "MAC.hpp"
 #include "Constants.hpp"
+#include "Buffer.hpp"
 
 namespace ZeroTier {
 
 /**
- * ZeroTier address, which doubles as the last 5 octets of the MAC on taps
- *
- * Natural sort order will differ on big vs. little endian machines, but that
- * won't matter when it's used as a local map/set key.
+ * A ZeroTier address
  */
 class Address
 {
-private:
-	union {
-		unsigned char o[ZT_ADDRESS_LENGTH];
-		uint64_t v;
-	} _a;
-
 public:
 	Address()
-		throw()
+		throw() :
+		_a(0)
 	{
-		_a.v = 0;
 	}
 
 	Address(const Address &a)
+		throw() :
+		_a(a._a)
+	{
+	}
+
+	Address(uint64_t a)
+		throw() :
+		_a(a & 0xffffffffffULL)
+	{
+	}
+
+	/**
+	 * @param bits Raw address -- 5 bytes, big-endian byte order
+	 */
+	Address(const void *bits)
+		throw()
+	{
+		setTo(bits);
+	}
+
+	inline Address &operator=(const Address &a)
 		throw()
 	{
-		_a.v = a._a.v;
+		_a = a._a;
+		return *this;
+	}
+
+	inline Address &operator=(const uint64_t a)
+		throw()
+	{
+		_a = (a & 0xffffffffffULL);
+		return *this;
 	}
 
 	/**
-	 * Create from a ZeroTier MAC
-	 *
-	 * @param m MAC (assumed to be a ZeroTier MAC)
+	 * @param bits Raw address -- 5 bytes, big-endian byte order
 	 */
-	Address(const MAC &m)
+	inline void setTo(const void *bits)
 		throw()
 	{
-		_a.v = 0;
-		for(int i=0;i<ZT_ADDRESS_LENGTH;++i)
-			_a.o[i] = m.data[i + 1];
+		const unsigned char *b = (const unsigned char *)bits;
+		uint64_t a = ((uint64_t)*b++) << 32;
+		a |= ((uint64_t)*b++) << 24;
+		a |= ((uint64_t)*b++) << 16;
+		a |= ((uint64_t)*b++) << 8;
+		a |= ((uint64_t)*b);
+		_a = a;
 	}
 
 	/**
-	 * @param bits Raw address -- 5 bytes in length
+	 * @param bits Buffer to hold 5-byte address in big-endian byte order
 	 */
-	Address(const void *bits)
+	inline void copyTo(void *bits) const
 		throw()
 	{
-		_a.v = 0;
-		for(int i=0;i<ZT_ADDRESS_LENGTH;++i)
-			_a.o[i] = ((const unsigned char *)bits)[i];
+		unsigned char *b = (unsigned char *)bits;
+		*(b++) = (unsigned char)((_a >> 32) & 0xff);
+		*(b++) = (unsigned char)((_a >> 24) & 0xff);
+		*(b++) = (unsigned char)((_a >> 16) & 0xff);
+		*(b++) = (unsigned char)((_a >> 8) & 0xff);
+		*b = (unsigned char)(_a & 0xff);
 	}
 
-	inline Address &operator=(const Address &a)
+	/**
+	 * Append to a buffer in big-endian byte order
+	 *
+	 * @param b Buffer to append to
+	 */
+	template<unsigned int C>
+	inline void appendTo(Buffer<C> &b) const
+		throw(std::out_of_range)
+	{
+		b.append((unsigned char)((_a >> 32) & 0xff));
+		b.append((unsigned char)((_a >> 24) & 0xff));
+		b.append((unsigned char)((_a >> 16) & 0xff));
+		b.append((unsigned char)((_a >> 8) & 0xff));
+		b.append((unsigned char)(_a & 0xff));
+	}
+
+	/**
+	 * @return String containing address as 5 binary bytes
+	 */
+	inline std::string toBinaryString() const
+	{
+		std::string b;
+		b.push_back((char)((_a >> 32) & 0xff));
+		b.push_back((char)((_a >> 24) & 0xff));
+		b.push_back((char)((_a >> 16) & 0xff));
+		b.push_back((char)((_a >> 8) & 0xff));
+		b.push_back((char)(_a & 0xff));
+		return b;
+	}
+
+	/**
+	 * @return Integer containing address (0 to 2^40)
+	 */
+	inline uint64_t toInt() const
 		throw()
 	{
-		_a.v = a._a.v;
-		return *this;
+		return _a;
 	}
 
 	/**
@@ -103,9 +164,7 @@ public:
 		throw()
 	{
 		MAC m;
-		m.data[0] = ZT_MAC_FIRST_OCTET;
-		for(int i=1;i<6;++i)
-			m.data[i] = _a.o[i - 1];
+		copyTo(m.data);
 		return m;
 	}
 
@@ -114,18 +173,15 @@ public:
 	 */
 	inline std::string toString() const
 	{
-		return Utils::hex(_a.o,ZT_ADDRESS_LENGTH);
+		char buf[16];
+		sprintf(buf,"%.10llx",_a);
+		return std::string(buf);
 	};
 
-	/**
-	 * Set address to zero
-	 */
-	inline void zero() throw() { _a.v = 0; }
-
 	/**
 	 * @return True if this address is not zero
 	 */
-	inline operator bool() const throw() { return (_a.v); }
+	inline operator bool() const throw() { return (_a); }
 
 	/**
 	 * @return Sum of all bytes in address
@@ -133,10 +189,7 @@ public:
 	inline unsigned int sum() const
 		throw()
 	{
-		unsigned int s = 0;
-		for(unsigned int i=0;i<ZT_ADDRESS_LENGTH;++i)
-			s += _a.o[i];
-		return s;
+		return (unsigned int)(((_a >> 32) & 0xff) + ((_a >> 24) & 0xff) + ((_a >> 16) & 0xff) + ((_a >> 8) & 0xff) + (_a & 0xff));
 	}
 
 	/**
@@ -151,23 +204,24 @@ public:
 	inline bool isReserved() const
 		throw()
 	{
-		return ((!_a.v)||(_a.o[0] == ZT_ADDRESS_RESERVED_PREFIX));
+		return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX));
 	}
 
-	inline unsigned char *data() throw() { return _a.o; }
-	inline const unsigned char *data() const throw() { return _a.o; }
-
-	inline unsigned int size() const throw() { return ZT_ADDRESS_LENGTH; }
+	/**
+	 * @param i Value from 0 to 4 (inclusive)
+	 * @return Byte at said position (address interpreted in big-endian order)
+	 */
+	inline unsigned char operator[](unsigned int i) const throw() { return (unsigned char)((_a >> (32 - (i * 8))) & 0xff); }
 
-	inline unsigned char &operator[](unsigned int i) throw() { return _a.o[i]; }
-	inline unsigned char operator[](unsigned int i) const throw() { return _a.o[i]; }
+	inline bool operator==(const Address &a) const throw() { return (_a == a._a); }
+	inline bool operator!=(const Address &a) const throw() { return (_a != a._a); }
+	inline bool operator>(const Address &a) const throw() { return (_a > a._a); }
+	inline bool operator<(const Address &a) const throw() { return (_a < a._a); }
+	inline bool operator>=(const Address &a) const throw() { return (_a >= a._a); }
+	inline bool operator<=(const Address &a) const throw() { return (_a <= a._a); }
 
-	inline bool operator==(const Address &a) const throw() { return (_a.v == a._a.v); }
-	inline bool operator!=(const Address &a) const throw() { return (_a.v != a._a.v); }
-	inline bool operator<(const Address &a) const throw() { return (_a.v < a._a.v); }
-	inline bool operator>(const Address &a) const throw() { return (_a.v > a._a.v); }
-	inline bool operator<=(const Address &a) const throw() { return (_a.v <= a._a.v); }
-	inline bool operator>=(const Address &a) const throw() { return (_a.v >= a._a.v); }
+private:
+	uint64_t _a;
 };
 
 } // namespace ZeroTier

+ 6 - 2
node/Identity.cpp

@@ -57,11 +57,13 @@ void Identity::generate()
 	// the address of an identity will be detected as its signature will be
 	// invalid. Of course, deep verification of address/key relationship is
 	// required to cover the more elaborate address claim jump attempt case.
+	unsigned char atmp[ZT_ADDRESS_LENGTH];
+	_address.copyTo(atmp);
 	SHA256_CTX sha;
 	unsigned char dig[32];
 	unsigned char idtype = IDENTITY_TYPE_NIST_P_521,zero = 0;
 	SHA256_Init(&sha);
-	SHA256_Update(&sha,_address.data(),ZT_ADDRESS_LENGTH);
+	SHA256_Update(&sha,atmp,ZT_ADDRESS_LENGTH);
 	SHA256_Update(&sha,&zero,1);
 	SHA256_Update(&sha,&idtype,1);
 	SHA256_Update(&sha,&zero,1);
@@ -73,11 +75,13 @@ void Identity::generate()
 
 bool Identity::locallyValidate(bool doAddressDerivationCheck) const
 {
+	unsigned char atmp[ZT_ADDRESS_LENGTH];
+	_address.copyTo(atmp);
 	SHA256_CTX sha;
 	unsigned char dig[32];
 	unsigned char idtype = IDENTITY_TYPE_NIST_P_521,zero = 0;
 	SHA256_Init(&sha);
-	SHA256_Update(&sha,_address.data(),ZT_ADDRESS_LENGTH);
+	SHA256_Update(&sha,atmp,ZT_ADDRESS_LENGTH);
 	SHA256_Update(&sha,&zero,1);
 	SHA256_Update(&sha,&idtype,1);
 	SHA256_Update(&sha,&zero,1);

+ 1 - 1
node/Identity.hpp

@@ -307,7 +307,7 @@ public:
 	inline void serialize(Buffer<C> &b,bool includePrivate = false) const
 		throw(std::out_of_range)
 	{
-		b.append(_address.data(),ZT_ADDRESS_LENGTH);
+		_address.appendTo(b);
 		b.append((unsigned char)IDENTITY_TYPE_NIST_P_521);
 		b.append((unsigned char)(_publicKey.size() & 0xff));
 		b.append(_publicKey.data(),_publicKey.size());

+ 4 - 4
node/Pack.cpp

@@ -62,7 +62,7 @@ const Pack::Entry *Pack::put(const std::string &name,const std::string &content)
 	SHA256_Update(&sha,content.data(),content.length());
 	SHA256_Final(e.sha256,&sha);
 
-	e.signedBy.zero();
+	e.signedBy = 0;
 	e.signature.assign((const char *)0,0);
 
 	return &e;
@@ -81,7 +81,7 @@ std::string Pack::serialize() const
 		entry.push_back(e->second.name);
 		entry.push_back(e->second.content);
 		entry.push_back(std::string((const char *)e->second.sha256,sizeof(e->second.sha256)));
-		entry.push_back(std::string((const char *)e->second.signedBy.data(),e->second.signedBy.size()));
+		entry.push_back(e->second.signedBy.toBinaryString());
 		entry.push_back(e->second.signature);
 		archive.push_back(entry.serialize());
 	}
@@ -123,8 +123,8 @@ bool Pack::deserialize(const void *sd,unsigned int sdlen)
 		memcpy(e.sha256,dig,32);
 
 		if (entry[3].length() == ZT_ADDRESS_LENGTH)
-			e.signedBy = entry[3].data();
-		else e.signedBy.zero();
+			e.signedBy.setTo(entry[3].data());
+		else e.signedBy = 0;
 		e.signature = entry[4];
 	}
 	return true;

+ 4 - 4
node/Switch.cpp

@@ -124,7 +124,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 		Packet outpTmpl(propPeers[0]->address(),_r->identity.address(),Packet::VERB_MULTICAST_FRAME);
 		outpTmpl.append((uint8_t)0);
 		outpTmpl.append((uint64_t)network->id());
-		outpTmpl.append(_r->identity.address().data(),ZT_ADDRESS_LENGTH);
+		_r->identity.address().appendTo(outpTmpl);
 		outpTmpl.append(from.data,6);
 		outpTmpl.append(mg.mac().data,6);
 		outpTmpl.append((uint32_t)mg.adi());
@@ -246,7 +246,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
 
 	{	// tell p1 where to find p2
 		Packet outp(p1,_r->identity.address(),Packet::VERB_RENDEZVOUS);
-		outp.append(p2.data(),ZT_ADDRESS_LENGTH);
+		p2.appendTo(outp);
 		outp.append((uint16_t)cg.first.port());
 		if (cg.first.isV6()) {
 			outp.append((unsigned char)16);
@@ -262,7 +262,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
 	}
 	{	// tell p2 where to find p1
 		Packet outp(p2,_r->identity.address(),Packet::VERB_RENDEZVOUS);
-		outp.append(p1.data(),ZT_ADDRESS_LENGTH);
+		p1.appendTo(outp);
 		outp.append((uint16_t)cg.second.port());
 		if (cg.second.isV6()) {
 			outp.append((unsigned char)16);
@@ -592,7 +592,7 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread
 	SharedPtr<Peer> supernode(_r->topology->getBestSupernode(peersAlreadyConsulted,numPeersAlreadyConsulted,false));
 	if (supernode) {
 		Packet outp(supernode->address(),_r->identity.address(),Packet::VERB_WHOIS);
-		outp.append(addr.data(),ZT_ADDRESS_LENGTH);
+		addr.appendTo(outp);
 		outp.encrypt(supernode->cryptKey());
 		outp.hmacSet(supernode->macKey());
 

+ 10 - 3
node/Topology.cpp

@@ -132,9 +132,12 @@ SharedPtr<Peer> Topology::getPeer(const Address &zta)
 			return ap->second;
 	}
 
+	unsigned char ztatmp[ZT_ADDRESS_LENGTH];
+	zta.copyTo(ztatmp);
+
 	Buffer<ZT_KISSDB_VALUE_SIZE> b(ZT_KISSDB_VALUE_SIZE);
 	_dbm_m.lock();
-	if (!KISSDB_get(&_dbm,zta.data(),b.data())) {
+	if (!KISSDB_get(&_dbm,ztatmp,b.data())) {
 		_dbm_m.unlock();
 
 		SharedPtr<Peer> p(new Peer());
@@ -305,11 +308,13 @@ void Topology::main()
 					for(std::map< Address,SharedPtr<Peer> >::iterator p(_activePeers.begin());p!=_activePeers.end();++p) {
 						if (p->second->getAndResetDirty()) {
 							try {
+								uint64_t atmp[ZT_ADDRESS_LENGTH];
+								p->second->identity().address().copyTo(atmp);
 								Buffer<ZT_PEER_MAX_SERIALIZED_LENGTH> b;
 								p->second->serialize(b);
 								b.zeroUnused();
 								_dbm_m.lock();
-								if (KISSDB_put(&_dbm,p->second->identity().address().data(),b.data())) {
+								if (KISSDB_put(&_dbm,atmp,b.data())) {
 									TRACE("error writing %s to peer.db",p->second->identity().address().toString().c_str());
 								}
 								_dbm_m.unlock();
@@ -334,11 +339,13 @@ void Topology::_reallyAddPeer(const SharedPtr<Peer> &p)
 		_activePeers[p->identity().address()] = p;
 	}
 	try {
+		uint64_t atmp[ZT_ADDRESS_LENGTH];
+		p->address().copyTo(atmp);
 		Buffer<ZT_PEER_MAX_SERIALIZED_LENGTH> b;
 		p->serialize(b);
 		b.zeroUnused();
 		_dbm_m.lock();
-		if (KISSDB_put(&_dbm,p->identity().address().data(),b.data())) {
+		if (KISSDB_put(&_dbm,atmp,b.data())) {
 			TRACE("error writing %s to peerdb",p->address().toString().c_str());
 		} else p->getAndResetDirty();
 		_dbm_m.unlock();