diff --git a/node/BandwidthAccount.hpp b/node/BandwidthAccount.hpp index aeba7eac6..b6ebfa3e5 100644 --- a/node/BandwidthAccount.hpp +++ b/node/BandwidthAccount.hpp @@ -69,11 +69,12 @@ public: * @param preload Initial balance to place in account * @param maxb Maximum allowed balance (> 0) * @param acc Rate of accrual in bytes per second + * @param now Current time */ - BandwidthAccount(uint32_t preload,uint32_t maxb,uint32_t acc) + BandwidthAccount(uint32_t preload,uint32_t maxb,uint32_t acc,uint64_t now) throw() { - init(preload,maxb,acc); + init(preload,maxb,acc,now); } /** @@ -82,11 +83,12 @@ public: * @param preload Initial balance to place in account * @param maxb Maximum allowed balance (> 0) * @param acc Rate of accrual in bytes per second + * @param now Current time */ - inline void init(uint32_t preload,uint32_t maxb,uint32_t acc) + inline void init(uint32_t preload,uint32_t maxb,uint32_t acc,uint64_t now) throw() { - _lastTime = Utils::nowf(); + _lastTime = ((double)now / 1000.0); _balance = preload; _maxBalance = maxb; _accrual = acc; @@ -95,15 +97,16 @@ public: /** * Update and retrieve balance of this account * + * @param now Current time * @return New balance updated from current clock */ - inline uint32_t update() + inline uint32_t update(uint64_t now) throw() { double lt = _lastTime; - double now = Utils::nowf(); - _lastTime = now; - return (_balance = std::min(_maxBalance,(uint32_t)round((double)_balance + ((double)_accrual * (now - lt))))); + double nowf = ((double)now / 1000.0); + _lastTime = nowf; + return (_balance = std::min(_maxBalance,(uint32_t)round((double)_balance + ((double)_accrual * (nowf - lt))))); } /** @@ -113,12 +116,13 @@ public: * balance is updated and false is returned. * * @param amt Amount to deduct + * @param now Current time * @return True if amount fit within balance and was deducted */ - inline bool deduct(uint32_t amt) + inline bool deduct(uint32_t amt,uint64_t now) throw() { - if (update() >= amt) { + if (update(now) >= amt) { _balance -= amt; return true; } diff --git a/node/Dictionary.cpp b/node/Dictionary.cpp index b702e5dbd..b3b015255 100644 --- a/node/Dictionary.cpp +++ b/node/Dictionary.cpp @@ -75,13 +75,13 @@ void Dictionary::fromString(const char *s,unsigned int maxlen) (*this)[keyBuf]; } -bool Dictionary::sign(const Identity &id) +bool Dictionary::sign(const Identity &id,uint64_t now) { try { // Sign identity and timestamp fields too. If there's an existing // signature, _mkSigBuf() ignores it. char nows[32]; - Utils::snprintf(nows,sizeof(nows),"%llx",(unsigned long long)Utils::now()); + Utils::snprintf(nows,sizeof(nows),"%llx",(unsigned long long)now); (*this)[ZT_DICTIONARY_SIGNATURE_IDENTITY] = id.toString(false); (*this)[ZT_DICTIONARY_SIGNATURE_TIMESTAMP] = nows; diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index c2742635f..afdc2d74c 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -289,9 +289,10 @@ public: * Add or update signature fields with a signature of all other keys and values * * @param with Identity to sign with (must have secret key) + * @param now Current time * @return True on success */ - bool sign(const Identity &id); + bool sign(const Identity &id,uint64_t now); /** * Verify signature against an identity diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index bc727deec..5940a78ec 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -74,11 +74,12 @@ public: * @param len Packet length * @param remoteAddress Address from which packet came * @param linkDesperation Link desperation for link over which packet was received + * @param now Current time * @throws std::out_of_range Range error processing packet */ - IncomingPacket(const void *data,unsigned int len,const InetAddress &remoteAddress,unsigned int linkDesperation) : + IncomingPacket(const void *data,unsigned int len,const InetAddress &remoteAddress,unsigned int linkDesperation,uint64_t now) : Packet(data,len), - _receiveTime(Utils::now()), + _receiveTime(now), _remoteAddress(remoteAddress), _linkDesperation(linkDesperation), __refCount() diff --git a/node/Network.cpp b/node/Network.cpp index 13c813442..1f762a917 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -350,7 +350,7 @@ bool Network::isAllowed(const Address &peer) const void Network::clean() { - uint64_t now = Utils::now(); + const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); if (_destroyed) @@ -386,6 +386,20 @@ void Network::clean() } } +bool Network::updateAndCheckMulticastBalance(const MulticastGroup &mg,unsigned int bytes) +{ + const uint64_t now = RR->node->now(); + Mutex::Lock _l(_lock); + if (!_config) + return false; + std::map< MulticastGroup,BandwidthAccount >::iterator bal(_multicastRateAccounts.find(mg)); + if (bal == _multicastRateAccounts.end()) { + NetworkConfig::MulticastRate r(_config->multicastRate(mg)); + bal = _multicastRateAccounts.insert(std::pair< MulticastGroup,BandwidthAccount >(mg,BandwidthAccount(r.preload,r.maxBalance,r.accrual,now))).first; + } + return bal->second.deduct(bytes,now); +} + void Network::learnBridgeRoute(const MAC &mac,const Address &addr) { Mutex::Lock _l(_lock); @@ -488,7 +502,7 @@ class _AnnounceMulticastGroupsToPeersWithActiveDirectPaths public: _AnnounceMulticastGroupsToPeersWithActiveDirectPaths(const RuntimeEnvironment *renv,Network *nw) : RR(renv), - _now(Utils::now()), + _now(renv->node->now()), _network(nw), _supernodeAddresses(renv->topology->supernodeAddresses()) {} diff --git a/node/Network.hpp b/node/Network.hpp index 930d15380..8938ff1d1 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -40,7 +40,6 @@ #include "Constants.hpp" #include "NonCopyable.hpp" -#include "Utils.hpp" #include "Address.hpp" #include "Mutex.hpp" #include "SharedPtr.hpp" @@ -230,18 +229,7 @@ public: * @param bytes Size of packet * @return True if packet is within budget */ - inline bool updateAndCheckMulticastBalance(const MulticastGroup &mg,unsigned int bytes) - { - Mutex::Lock _l(_lock); - if (!_config) - return false; - std::map< MulticastGroup,BandwidthAccount >::iterator bal(_multicastRateAccounts.find(mg)); - if (bal == _multicastRateAccounts.end()) { - NetworkConfig::MulticastRate r(_config->multicastRate(mg)); - bal = _multicastRateAccounts.insert(std::pair< MulticastGroup,BandwidthAccount >(mg,BandwidthAccount(r.preload,r.maxBalance,r.accrual))).first; - } - return bal->second.deduct(bytes); - } + bool updateAndCheckMulticastBalance(const MulticastGroup &mg,unsigned int bytes); /** * Get current network config or throw exception diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index ba72a415e..3aefba4ca 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -43,7 +43,7 @@ SharedPtr NetworkConfig::createTestNetworkConfig(const Address &s memset(nc->_etWhitelist,0,sizeof(nc->_etWhitelist)); nc->_etWhitelist[0] |= 1; // allow all nc->_nwid = ZT_TEST_NETWORK_ID; - nc->_timestamp = Utils::now(); + nc->_timestamp = 1; nc->_revision = 1; nc->_issuedTo = self; nc->_multicastLimit = ZT_MULTICAST_DEFAULT_LIMIT; diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index ed2c33cb2..7caa27a75 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -106,7 +106,7 @@ void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toA { if (_haveCom) { SharedPtr network(RR->nc->network(_nwid)); - if (network->peerNeedsOurMembershipCertificate(toAddr,Utils::now())) { + if (network->peerNeedsOurMembershipCertificate(toAddr,RR->node->now())) { _packetWithCom.newInitializationVector(); _packetWithCom.setDestination(toAddr); //TRACE(">>MC %.16llx -> %s (with COM)",(unsigned long long)this,toAddr.toString().c_str()); diff --git a/node/Switch.cpp b/node/Switch.cpp index df5b4f2aa..7106503c0 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -91,7 +91,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c * Note: even when we introduce a more purposeful binding of the main UDP port, this can * 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())) { + if (!RR->antiRec->checkEthernetFrame(data,len)) { TRACE("%.16llx: rejected recursively addressed ZeroTier packet by tail match (type %s, length: %u)",network->id(),etherTypeName(etherType),data.size()); return; } @@ -115,14 +115,24 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c if (to.isMulticast()) { // Destination is a multicast address (including broadcast) - uint64_t now = Utils::now(); + const uint64_t now = RR->node->now(); MulticastGroup mg(to,0); if (to.isBroadcast()) { - if ((etherType == ZT_ETHERTYPE_ARP)&&(data.size() >= 28)&&(data[2] == 0x08)&&(data[3] == 0x00)&&(data[4] == 6)&&(data[5] == 4)&&(data[7] == 0x01)) { + if ( + (etherType == ZT_ETHERTYPE_ARP)&& + (len >= 28)&& + ( + (((const unsigned char *)data)[2] == 0x08)&& + (((const unsigned char *)data)[3] == 0x00)&& + (((const unsigned char *)data)[4] == 6)&& + (((const unsigned char *)data)[5] == 4)&& + (((const unsigned char *)data)[7] == 0x01) + ) + ) { // Cram IPv4 IP into ADI field to make IPv4 ARP broadcast channel specific and scalable // Also: enableBroadcast() does not apply to ARP since it's required for IPv4 - mg = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(data.field(24,4),4,0)); + mg = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); } else if (!nconf->enableBroadcast()) { // Don't transmit broadcasts if this network doesn't want them TRACE("%.16llx: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled",network->id()); @@ -138,7 +148,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c network->learnBridgedMulticastGroup(mg,now); // Check multicast/broadcast bandwidth quotas and reject if quota exceeded - if (!network->updateAndCheckMulticastBalance(mg,data.size())) { + if (!network->updateAndCheckMulticastBalance(mg,len)) { TRACE("%.16llx: didn't multicast %d bytes, quota exceeded for multicast group %s",network->id(),(int)data.size(),mg.toString().c_str()); return; } @@ -154,8 +164,8 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c mg, (fromBridged) ? from : MAC(), etherType, - data.data(), - data.size()); + data, + len); return; } @@ -165,7 +175,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c Address toZT(to.toAddress(network->id())); if (network->isAllowed(toZT)) { - if (network->peerNeedsOurMembershipCertificate(toZT,Utils::now())) { + if (network->peerNeedsOurMembershipCertificate(toZT,RR->node->now())) { // TODO: once there are no more <1.0.0 nodes around, we can // bundle this with EXT_FRAME instead of sending two packets. Packet outp(toZT,RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); @@ -181,7 +191,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c to.appendTo(outp); from.appendTo(outp); outp.append((uint16_t)etherType); - outp.append(data); + outp.append(data,len); outp.compress(); send(outp,true); } else { @@ -189,7 +199,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); outp.append(network->id()); outp.append((uint16_t)etherType); - outp.append(data); + outp.append(data,len); outp.compress(); send(outp,true); } @@ -245,7 +255,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c to.appendTo(outp); from.appendTo(outp); outp.append((uint16_t)etherType); - outp.append(data); + outp.append(data,len); outp.compress(); send(outp,true); } @@ -261,7 +271,7 @@ void Switch::send(const Packet &packet,bool encrypt) if (!_trySend(packet,encrypt)) { Mutex::Lock _l(_txQueue_m); - _txQueue.insert(std::pair< Address,TXQueueEntry >(packet.destination(),TXQueueEntry(Utils::now(),packet,encrypt))); + _txQueue.insert(std::pair< Address,TXQueueEntry >(packet.destination(),TXQueueEntry(RR->node->now(),packet,encrypt))); } } @@ -277,7 +287,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force) if (!p2p) return false; - uint64_t now = Utils::now(); + const uint64_t now = RR->node->now(); std::pair cg(Peer::findCommonGround(*p1p,*p2p,now)); if (!(cg.first)) @@ -375,7 +385,7 @@ void Switch::requestWhois(const Address &addr) Mutex::Lock _l(_outstandingWhoisRequests_m); std::pair< std::map< Address,WhoisRequest >::iterator,bool > entry(_outstandingWhoisRequests.insert(std::pair(addr,WhoisRequest()))); if ((inserted = entry.second)) - entry.first->second.lastSent = Utils::now(); + entry.first->second.lastSent = RR->node->now(); entry.first->second.retries = 0; // reset retry count if entry already existed } if (inserted) @@ -597,7 +607,7 @@ void Switch::_handleRemotePacketFragment(const InetAddress &fromAddr,int linkDes // We received a Packet::Fragment without its head, so queue it and wait DefragQueueEntry &dq = _defragQueue[pid]; - dq.creationTime = Utils::now(); + dq.creationTime = RR->node->now(); dq.frags[fno - 1] = fragment; dq.totalFragments = tf; // total fragment count is known dq.haveFragments = 1 << fno; // we have only this fragment @@ -630,7 +640,7 @@ void Switch::_handleRemotePacketFragment(const InetAddress &fromAddr,int linkDes void Switch::_handleRemotePacketHead(const InetAddress &fromAddr,int linkDesperation,const void *data,unsigned int len) { - SharedPtr packet(new IncomingPacket(data,len,fromAddr,linkDesperation)); + SharedPtr packet(new IncomingPacket(data,len,fromAddr,linkDesperation,RR->node->now())); Address source(packet->source()); Address destination(packet->destination()); @@ -664,7 +674,7 @@ void Switch::_handleRemotePacketHead(const InetAddress &fromAddr,int linkDespera if (dqe == _defragQueue.end()) { // If we have no other fragments yet, create an entry and save the head DefragQueueEntry &dq = _defragQueue[pid]; - dq.creationTime = Utils::now(); + dq.creationTime = RR->node->now(); dq.frag0 = packet; dq.totalFragments = 0; // 0 == unknown, waiting for Packet::Fragment dq.haveFragments = 1; // head is first bit (left to right)