Browse Source

timestamps changed from uint64_t to int64_t

There were cases in the code where time calculations and comparisons were overflowing and causing connection instability.  This will keep time calculations within expected ranges.
pull/1/head
Grant Limberg 9 years ago
parent
commit
b1d60df44c
  1. 14
      controller/EmbeddedNetworkController.cpp
  2. 8
      controller/EmbeddedNetworkController.hpp
  3. 4
      controller/JSONDB.cpp
  4. 2
      controller/JSONDB.hpp
  5. 12
      include/ZeroTierOne.h
  6. 2
      node/CertificateOfMembership.hpp
  7. 12
      node/IncomingPacket.cpp
  8. 4
      node/IncomingPacket.hpp
  9. 8
      node/Membership.cpp
  10. 14
      node/Membership.hpp
  11. 8
      node/Multicaster.cpp
  12. 12
      node/Multicaster.hpp
  13. 10
      node/Network.cpp
  14. 4
      node/Network.hpp
  15. 34
      node/Node.cpp
  16. 26
      node/Node.hpp
  17. 2
      node/OutboundMulticast.hpp
  18. 2
      node/Path.cpp
  19. 22
      node/Path.hpp
  20. 35
      node/Peer.cpp
  21. 76
      node/Peer.hpp
  22. 4
      node/Revocation.hpp
  23. 6
      node/SelfAwareness.cpp
  24. 4
      node/SelfAwareness.hpp
  25. 20
      node/Switch.cpp
  26. 14
      node/Switch.hpp
  27. 7
      node/Topology.cpp
  28. 4
      node/Topology.hpp
  29. 6
      one.cpp
  30. 6
      osdep/OSUtils.hpp
  31. 2
      osdep/PortMapper.cpp
  32. 22
      service/OneService.cpp
  33. 2
      service/SoftwareUpdater.cpp
  34. 2
      service/SoftwareUpdater.hpp

14
controller/EmbeddedNetworkController.cpp

@ -535,7 +535,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET(
} else {
// Get network
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
JSONDB::NetworkSummaryInfo ns;
_db.getNetworkSummaryInfo(nwid,ns);
_addNetworkNonPersistedFields(network,now,ns);
@ -602,7 +602,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
responseContentType = "application/json";
return 400;
}
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
if (path[0] == "network") {
@ -1087,7 +1087,7 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt)
}
}
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
OSUtils::ztsnprintf(id,sizeof(id),"%.10llx-%.10llx-%.16llx-%.8lx",_signingId.address().toInt(),rt.origin,now,++idCounter);
d["id"] = id;
d["objtype"] = "trace";
@ -1129,7 +1129,7 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt)
void EmbeddedNetworkController::onNetworkUpdate(const uint64_t networkId)
{
// Send an update to all members of the network that are online
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
Mutex::Lock _l(_memberStatus_m);
for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) {
if ((i->first.networkId == networkId)&&(i->second.online(now))&&(i->second.lastRequestMetaData))
@ -1150,7 +1150,7 @@ void EmbeddedNetworkController::onNetworkMemberUpdate(const uint64_t networkId,c
void EmbeddedNetworkController::onNetworkMemberDeauthorize(const uint64_t networkId,const uint64_t memberId)
{
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
Revocation rev((uint32_t)_node->prng(),networkId,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(memberId),Revocation::CREDENTIAL_TYPE_COM);
rev.sign(_signingId);
{
@ -1224,7 +1224,7 @@ void EmbeddedNetworkController::_request(
if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender))
return;
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
if (requestPacketId) {
Mutex::Lock _l(_memberStatus_m);
@ -1360,7 +1360,7 @@ void EmbeddedNetworkController::_request(
// If we made it this far, they are authorized.
// -------------------------------------------------------------------------
uint64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA;
int64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA;
if (now > ns.mostRecentDeauthTime) {
// If we recently de-authorized a member, shrink credential TTL/max delta to
// be below the threshold required to exclude it. Cap this to a min/max to

8
controller/EmbeddedNetworkController.hpp

@ -166,7 +166,7 @@ private:
}
network["objtype"] = "network";
}
inline void _addNetworkNonPersistedFields(nlohmann::json &network,uint64_t now,const JSONDB::NetworkSummaryInfo &ns)
inline void _addNetworkNonPersistedFields(nlohmann::json &network,int64_t now,const JSONDB::NetworkSummaryInfo &ns)
{
network["clock"] = now;
network["authorizedMemberCount"] = ns.authorizedMemberCount;
@ -182,7 +182,7 @@ private:
// legacy fields
network.erase("lastModified");
}
inline void _addMemberNonPersistedFields(uint64_t nwid,uint64_t nodeId,nlohmann::json &member,uint64_t now)
inline void _addMemberNonPersistedFields(uint64_t nwid,uint64_t nodeId,nlohmann::json &member,int64_t now)
{
member["clock"] = now;
Mutex::Lock _l(_memberStatus_m);
@ -197,7 +197,7 @@ private:
member.erase("lastRequestMetaData");
}
const uint64_t _startTime;
const int64_t _startTime;
volatile bool _running;
BlockingQueue<_RQEntry *> _queue;
@ -230,7 +230,7 @@ private:
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastRequestMetaData;
Identity identity;
InetAddress physicalAddr; // last known physical address
inline bool online(const uint64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); }
inline bool online(const int64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); }
};
struct _MemberStatusHash
{

4
controller/JSONDB.cpp

@ -323,7 +323,7 @@ void JSONDB::threadMain()
_networks_m.unlock();
}
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
try {
Mutex::Lock _l(_networks_m);
for(std::vector<uint64_t>::iterator ii(todo.begin());ii!=todo.end();++ii) {
@ -373,7 +373,7 @@ void JSONDB::threadMain()
} catch ( ... ) {}
} else {
try {
ns.mostRecentDeauthTime = std::max(ns.mostRecentDeauthTime,OSUtils::jsonInt(member["lastDeauthorizedTime"],0ULL));
ns.mostRecentDeauthTime = std::max(ns.mostRecentDeauthTime,(int64_t)OSUtils::jsonInt(member["lastDeauthorizedTime"],0LL));
} catch ( ... ) {}
}
++ns.totalMemberCount;

2
controller/JSONDB.hpp

@ -57,7 +57,7 @@ public:
unsigned long authorizedMemberCount;
unsigned long activeMemberCount;
unsigned long totalMemberCount;
uint64_t mostRecentDeauthTime;
int64_t mostRecentDeauthTime;
};
JSONDB(const std::string &basePath,EmbeddedNetworkController *parent);

12
include/ZeroTierOne.h

@ -1587,7 +1587,7 @@ struct ZT_Node_Callbacks
* @param now Current clock in milliseconds
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now);
ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now);
/**
* Delete a node and free all resources it consumes
@ -1615,12 +1615,12 @@ ZT_SDK_API void ZT_Node_delete(ZT_Node *node);
ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket(
ZT_Node *node,
void *tptr,
uint64_t now,
int64_t now,
int64_t localSocket,
const struct sockaddr_storage *remoteAddress,
const void *packetData,
unsigned int packetLength,
volatile uint64_t *nextBackgroundTaskDeadline);
volatile int64_t *nextBackgroundTaskDeadline);
/**
* Process a frame from a virtual network port (tap)
@ -1641,7 +1641,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket(
ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
ZT_Node *node,
void *tptr,
uint64_t now,
int64_t now,
uint64_t nwid,
uint64_t sourceMac,
uint64_t destMac,
@ -1649,7 +1649,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
unsigned int vlanId,
const void *frameData,
unsigned int frameLength,
volatile uint64_t *nextBackgroundTaskDeadline);
volatile int64_t *nextBackgroundTaskDeadline);
/**
* Perform periodic background operations
@ -1660,7 +1660,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
* @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline);
ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline);
/**
* Join a network

2
node/CertificateOfMembership.hpp

@ -176,7 +176,7 @@ public:
/**
* @return Timestamp for this cert and maximum delta for timestamp
*/
inline uint64_t timestamp() const
inline int64_t timestamp() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP)

12
node/IncomingPacket.cpp

@ -169,7 +169,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
// Peers can send this in response to frames if they do not have a recent enough COM from us
networkId = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD);
const SharedPtr<Network> network(RR->node->network(networkId));
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) )
network->pushCredentialsNow(tPtr,peer->address(),now);
} break;
@ -202,7 +202,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated)
{
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
const uint64_t pid = packetId();
const Address fromAddress(source());
@ -210,7 +210,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION];
const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION];
const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO_IDX_REVISION);
const uint64_t timestamp = at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP);
const int64_t timestamp = at<int64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP);
Identity id;
unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
@ -725,7 +725,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share
bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
uint64_t authOnNetwork[256]; // cache for approved network IDs
unsigned int authOnNetworkCount = 0;
@ -1082,7 +1082,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
// First, subject this to a rate limit
if (!peer->rateGatePushDirectPaths(now)) {
@ -1186,7 +1186,7 @@ bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,con
void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid)
{
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
if (peer->rateGateOutgoingComRequest(now)) {
Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR);
outp.append((uint8_t)verb());

4
node/IncomingPacket.hpp

@ -77,7 +77,7 @@ public:
* @param now Current time
* @throws std::out_of_range Range error processing packet
*/
IncomingPacket(const void *data,unsigned int len,const SharedPtr<Path> &path,uint64_t now) :
IncomingPacket(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now) :
Packet(data,len),
_receiveTime(now),
_path(path)
@ -93,7 +93,7 @@ public:
* @param now Current time
* @throws std::out_of_range Range error processing packet
*/
inline void init(const void *data,unsigned int len,const SharedPtr<Path> &path,uint64_t now)
inline void init(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now)
{
copyFrom(data,len);
_receiveTime = now;

8
node/Membership.cpp

@ -51,7 +51,7 @@ Membership::Membership() :
resetPushState();
}
void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force)
void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force)
{
bool sendCom = ( (nconf.com) && ( ((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) );
@ -127,13 +127,13 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const u
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com)
{
const uint64_t newts = com.timestamp();
const int64_t newts = com.timestamp();
if (newts <= _comRevocationThreshold) {
RR->t->credentialRejected(tPtr,com,"revoked");
return ADD_REJECTED;
}
const uint64_t oldts = _com.timestamp();
const int64_t oldts = _com.timestamp();
if (newts < oldts) {
RR->t->credentialRejected(tPtr,com,"old");
return ADD_REJECTED;
@ -227,7 +227,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
}
}
void Membership::clean(const uint64_t now,const NetworkConfig &nconf)
void Membership::clean(const int64_t now,const NetworkConfig &nconf)
{
_cleanCredImpl<Tag>(nconf,_remoteTags);
_cleanCredImpl<Capability>(nconf,_remoteCaps);

14
node/Membership.hpp

@ -80,7 +80,7 @@ public:
* @param localCapabilityIndex Index of local capability to include (in nconf.capabilities[]) or -1 if none
* @param force If true, send objects regardless of last push time
*/
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force);
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force);
/**
* Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true
@ -88,7 +88,7 @@ public:
* @param now Current time
* @return True if we should update multicasts
*/
inline bool multicastLikeGate(const uint64_t now)
inline bool multicastLikeGate(const int64_t now)
{
if ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD) {
_lastUpdatedMulticast = now;
@ -110,7 +110,7 @@ public:
return nconf.com.agreesWith(_com);
}
inline bool recentlyAssociated(const uint64_t now) const
inline bool recentlyAssociated(const int64_t now) const
{
return ((_com)&&((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT));
}
@ -180,7 +180,7 @@ public:
* @param now Current time
* @param nconf Current network configuration
*/
void clean(const uint64_t now,const NetworkConfig &nconf);
void clean(const int64_t now,const NetworkConfig &nconf);
/**
* Reset last pushed time for local credentials
@ -223,13 +223,13 @@ private:
}
// Last time we pushed MULTICAST_LIKE(s)
uint64_t _lastUpdatedMulticast;
int64_t _lastUpdatedMulticast;
// Last time we pushed our COM to this peer
uint64_t _lastPushedCom;
int64_t _lastPushedCom;
// Revocation threshold for COM or 0 if none
uint64_t _comRevocationThreshold;
int64_t _comRevocationThreshold;
// Remote member's latest network COM
CertificateOfMembership _com;

8
node/Multicaster.cpp

@ -51,7 +51,7 @@ Multicaster::~Multicaster()
{
}
void Multicaster::addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown)
void Multicaster::addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown)
{
const unsigned char *p = (const unsigned char *)addresses;
const unsigned char *e = p + (5 * count);
@ -160,7 +160,7 @@ std::vector<Address> Multicaster::getMembers(uint64_t nwid,const MulticastGroup
void Multicaster::send(
void *tPtr,
unsigned int limit,
uint64_t now,
int64_t now,
uint64_t nwid,
bool disableCompression,
const std::vector<Address> &alwaysSendTo,
@ -309,7 +309,7 @@ void Multicaster::send(
delete [] indexes;
}
void Multicaster::clean(uint64_t now)
void Multicaster::clean(int64_t now)
{
{
Mutex::Lock _l(_groups_m);
@ -367,7 +367,7 @@ void Multicaster::addCredential(void *tPtr,const CertificateOfMembership &com,bo
}
}
void Multicaster::_add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member)
void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member)
{
// assumes _groups_m is locked

12
node/Multicaster.hpp

@ -98,7 +98,7 @@ public:
* @param mg Multicast group
* @param member New member address
*/
inline void add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member)
inline void add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member)
{
Mutex::Lock _l(_groups_m);
_add(tPtr,now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member);
@ -117,7 +117,7 @@ public:
* @param count Number of addresses
* @param totalKnown Total number of known addresses as reported by peer
*/
void addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown);
void addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown);
/**
* Remove a multicast group member (if present)
@ -174,7 +174,7 @@ public:
void send(
void *tPtr,
unsigned int limit,
uint64_t now,
int64_t now,
uint64_t nwid,
bool disableCompression,
const std::vector<Address> &alwaysSendTo,
@ -190,7 +190,7 @@ public:
* @param RR Runtime environment
* @param now Current time
*/
void clean(uint64_t now);
void clean(int64_t now);
/**
* Add an authorization credential
@ -212,7 +212,7 @@ public:
* @param now Current time
* @return True if GATHER and LIKE should be allowed
*/
bool cacheAuthorized(const Address &a,const uint64_t nwid,const uint64_t now) const
bool cacheAuthorized(const Address &a,const uint64_t nwid,const int64_t now) const
{
Mutex::Lock _l(_gatherAuth_m);
const uint64_t *p = _gatherAuth.get(_GatherAuthKey(nwid,a));
@ -220,7 +220,7 @@ public:
}
private:
void _add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member);
void _add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member);
const RuntimeEnvironment *RR;

10
node/Network.cpp

@ -592,7 +592,7 @@ bool Network::filterOutgoingPacket(
const unsigned int etherType,
const unsigned int vlanId)
{
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
Address ztFinalDest(ztDest);
int localCapabilityIndex = -1;
int accept = 0;
@ -1164,7 +1164,7 @@ void Network::requestConfiguration(void *tPtr)
bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer)
{
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
Mutex::Lock _l(_lock);
try {
if (_config) {
@ -1192,7 +1192,7 @@ bool Network::recentlyAssociatedWith(const Address &addr)
void Network::clean()
{
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
Mutex::Lock _l(_lock);
if (_destroyed)
@ -1257,7 +1257,7 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
}
}
void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now)
void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now)
{
Mutex::Lock _l(_lock);
const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size();
@ -1377,7 +1377,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup)
{
// Assumes _lock is locked
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
std::vector<MulticastGroup> groups;
if (newMulticastGroup)

4
node/Network.hpp

@ -305,7 +305,7 @@ public:
* @param mg Multicast group
* @param now Current time
*/
void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now);
void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now);
/**
* Validate a credential and learn it if it passes certificate and other checks
@ -357,7 +357,7 @@ public:
* @param to Destination peer address
* @param now Current time
*/
inline void pushCredentialsNow(void *tPtr,const Address &to,const uint64_t now)
inline void pushCredentialsNow(void *tPtr,const Address &to,const int64_t now)
{
Mutex::Lock _l(_lock);
_membership(to).pushCredentials(RR,tPtr,now,to,_config,-1,true);

34
node/Node.cpp

@ -54,7 +54,7 @@ namespace ZeroTier {
/* Public Node interface (C++, exposed via CAPI bindings) */
/****************************************************************************/
Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) :
Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now) :
_RR(this),
RR(&_RR),
_uPtr(uptr),
@ -139,12 +139,12 @@ Node::~Node()
ZT_ResultCode Node::processWirePacket(
void *tptr,
uint64_t now,
int64_t now,
int64_t localSocket,
const struct sockaddr_storage *remoteAddress,
const void *packetData,
unsigned int packetLength,
volatile uint64_t *nextBackgroundTaskDeadline)
volatile int64_t *nextBackgroundTaskDeadline)
{
_now = now;
RR->sw->onRemotePacket(tptr,localSocket,*(reinterpret_cast<const InetAddress *>(remoteAddress)),packetData,packetLength);
@ -153,7 +153,7 @@ ZT_ResultCode Node::processWirePacket(
ZT_ResultCode Node::processVirtualNetworkFrame(
void *tptr,
uint64_t now,
int64_t now,
uint64_t nwid,
uint64_t sourceMac,
uint64_t destMac,
@ -161,7 +161,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
unsigned int vlanId,
const void *frameData,
unsigned int frameLength,
volatile uint64_t *nextBackgroundTaskDeadline)
volatile int64_t *nextBackgroundTaskDeadline)
{
_now = now;
SharedPtr<Network> nw(this->network(nwid));
@ -175,7 +175,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
class _PingPeersThatNeedPing
{
public:
_PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector<InetAddress> > &upstreamsToContact,uint64_t now) :
_PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector<InetAddress> > &upstreamsToContact,int64_t now) :
lastReceiveFromUpstream(0),
RR(renv),
_tPtr(tPtr),
@ -185,7 +185,7 @@ public:
{
}
uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay
int64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay
inline void operator()(Topology &t,const SharedPtr<Peer> &p)
{
@ -234,17 +234,17 @@ private:
const RuntimeEnvironment *RR;
void *_tPtr;
Hashtable< Address,std::vector<InetAddress> > &_upstreamsToContact;
const uint64_t _now;
const int64_t _now;
const SharedPtr<Peer> _bestCurrentUpstream;
};
ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline)
ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
{
_now = now;
Mutex::Lock bl(_backgroundTasksLock);
unsigned long timeUntilNextPingCheck = ZT_PING_CHECK_INVERVAL;
const uint64_t timeSinceLastPingCheck = now - _lastPingCheck;
const int64_t timeSinceLastPingCheck = now - _lastPingCheck;
if (timeSinceLastPingCheck >= ZT_PING_CHECK_INVERVAL) {
try {
_lastPingCheck = now;
@ -305,7 +305,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint
}
try {
*nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY);
*nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY);
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
@ -689,7 +689,7 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des
extern "C" {
enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now)
enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now)
{
*node = (ZT_Node *)0;
try {
@ -714,12 +714,12 @@ void ZT_Node_delete(ZT_Node *node)
enum ZT_ResultCode ZT_Node_processWirePacket(
ZT_Node *node,
void *tptr,
uint64_t now,
int64_t now,
int64_t localSocket,
const struct sockaddr_storage *remoteAddress,
const void *packetData,
unsigned int packetLength,
volatile uint64_t *nextBackgroundTaskDeadline)
volatile int64_t *nextBackgroundTaskDeadline)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->processWirePacket(tptr,now,localSocket,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline);
@ -733,7 +733,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket(
enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
ZT_Node *node,
void *tptr,
uint64_t now,
int64_t now,
uint64_t nwid,
uint64_t sourceMac,
uint64_t destMac,
@ -741,7 +741,7 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
unsigned int vlanId,
const void *frameData,
unsigned int frameLength,
volatile uint64_t *nextBackgroundTaskDeadline)
volatile int64_t *nextBackgroundTaskDeadline)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->processVirtualNetworkFrame(tptr,now,nwid,sourceMac,destMac,etherType,vlanId,frameData,frameLength,nextBackgroundTaskDeadline);
@ -752,7 +752,7 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
}
}
enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline)
enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->processBackgroundTasks(tptr,now,nextBackgroundTaskDeadline);

26
node/Node.hpp

@ -64,7 +64,7 @@ class World;
class Node : public NetworkController::Sender
{
public:
Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now);
Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now);
virtual ~Node();
// Get rid of alignment warnings on 32-bit Windows and possibly improve performance
@ -77,15 +77,15 @@ public:
ZT_ResultCode processWirePacket(
void *tptr,
uint64_t now,
int64_t now,
int64_t localSocket,
const struct sockaddr_storage *remoteAddress,
const void *packetData,
unsigned int packetLength,
volatile uint64_t *nextBackgroundTaskDeadline);
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processVirtualNetworkFrame(
void *tptr,
uint64_t now,
int64_t now,
uint64_t nwid,
uint64_t sourceMac,
uint64_t destMac,
@ -93,8 +93,8 @@ public:
unsigned int vlanId,
const void *frameData,
unsigned int frameLength,
volatile uint64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline);
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr);
ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr);
ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
@ -114,7 +114,7 @@ public:
// Internal functions ------------------------------------------------------
inline uint64_t now() const { return _now; }
inline int64_t now() const { return _now; }
inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
{
@ -243,7 +243,7 @@ public:
* @param from Source address of packet
* @return True if within rate limits
*/
inline bool rateGateIdentityVerification(const uint64_t now,const InetAddress &from)
inline bool rateGateIdentityVerification(const int64_t now,const InetAddress &from)
{
unsigned long iph = from.rateGateHash();
if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) {
@ -270,7 +270,7 @@ private:
uint32_t _expectingRepliesTo[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1][ZT_EXPECTING_REPLIES_BUCKET_MASK2 + 1];
// Time of last identity verification indexed by InetAddress.rateGateHash() -- used in IncomingPacket::_doHELLO() via rateGateIdentityVerification()
uint64_t _lastIdentityVerification[16384];
int64_t _lastIdentityVerification[16384];
Hashtable< uint64_t,SharedPtr<Network> > _networks;
Mutex _networks_m;
@ -281,10 +281,10 @@ private:
Mutex _backgroundTasksLock;
Address _remoteTraceTarget;
uint64_t _now;
uint64_t _lastPingCheck;
uint64_t _lastHousekeepingRun;
volatile uint64_t _prngState[2];
int64_t _now;
int64_t _lastPingCheck;
int64_t _lastHousekeepingRun;
volatile int64_t _prngState[2];
bool _online;
};

2
node/OutboundMulticast.hpp

@ -96,7 +96,7 @@ public:
* @param now Current time
* @return True if this multicast is expired (has exceeded transmit timeout)
*/
inline bool expired(uint64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); }
inline bool expired(int64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); }
/**
* @return True if this outbound multicast has been sent to enough peers

2
node/Path.cpp

@ -30,7 +30,7 @@
namespace ZeroTier {
bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now)
bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now)
{
if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) {
_lastOut = now;

22
node/Path.hpp

@ -179,14 +179,14 @@ public:
* @param now Current time
* @return True if transport reported success
*/
bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now);
bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now);
/**
* Manually update last sent time
*
* @param t Time of send
*/
inline void sent(const uint64_t t) { _lastOut = t; }
inline void sent(const int64_t t) { _lastOut = t; }
/**
* @return Local socket as specified by external code
@ -206,7 +206,7 @@ public:
/**
* @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
*/
inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
/**
* @return Preference rank, higher == better
@ -261,27 +261,27 @@ public:
/**
* @return True if path appears alive
*/
inline bool alive(const uint64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); }
inline bool alive(const int64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); }
/**
* @return True if this path needs a heartbeat
*/
inline bool needsHeartbeat(const uint64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); }
inline bool needsHeartbeat(const int64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); }
/**
* @return Last time we sent something
*/
inline uint64_t lastOut() const { return _lastOut; }
inline int64_t lastOut() const { return _lastOut; }
/**
* @return Last time we received anything
*/
inline uint64_t lastIn() const { return _lastIn; }
inline int64_t lastIn() const { return _lastIn; }
/**
* @return Time last trust-established packet was received
*/
inline uint64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; }
inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; }
/**
* Return and increment outgoing packet counter (used with Packet::armor())
@ -291,9 +291,9 @@ public:
inline unsigned int nextOutgoingCounter() { return _outgoingPacketCounter++; }
private:
volatile uint64_t _lastOut;
volatile uint64_t _lastIn;
volatile uint64_t _lastTrustEstablishedPacketReceived;
volatile int64_t _lastOut;
volatile int64_t _lastIn;
volatile int64_t _lastTrustEstablishedPacketReceived;
volatile uint64_t _incomingLinkQualityFastLog;
int64_t _localSocket;
volatile unsigned long _incomingLinkQualitySlowLogPtr;

35
node/Peer.cpp

@ -34,6 +34,7 @@
#include "SelfAwareness.hpp"
#include "Packet.hpp"
#include "Trace.hpp"
#include "InetAddress.hpp"
namespace ZeroTier {
@ -75,7 +76,7 @@ void Peer::received(
const bool trustEstablished,
const uint64_t networkId)
{
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
/*
#ifdef ZT_ENABLE_CLUSTER
@ -263,14 +264,14 @@ void Peer::received(
}
}
bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force)
bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force)
{
Mutex::Lock _l(_paths_m);
uint64_t v6lr = 0;
int64_t v6lr = 0;
if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) )
v6lr = _v6Path.p->lastIn();
uint64_t v4lr = 0;
int64_t v4lr = 0;
if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) )
v4lr = _v4Path.p->lastIn();
@ -289,16 +290,18 @@ bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,
return false;
}
SharedPtr<Path> Peer::getBestPath(uint64_t now,bool includeExpired)
SharedPtr<Path> Peer::getBestPath(int64_t now,bool includeExpired)
{
Mutex::Lock _l(_paths_m);
uint64_t v6lr = 0;
if ( ( includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v6Path.p) )
int64_t v6lr = 0;
if ((includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)) && (_v6Path.p)) {
v6lr = _v6Path.p->lastIn();
uint64_t v4lr = 0;
if ( ( includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v4Path.p) )
}
int64_t v4lr = 0;
if ((includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)) && (_v4Path.p)) {
v4lr = _v4Path.p->lastIn();
}
if (v6lr > v4lr) {
return _v6Path.p;
@ -309,7 +312,7 @@ SharedPtr<Path> Peer::getBestPath(uint64_t now,bool includeExpired)
return SharedPtr<Path>();
}
void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter)
void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter)
{
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO);
@ -357,7 +360,7 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
}
}
void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter)
void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello,unsigned int counter)
{
if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
@ -369,7 +372,7 @@ void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAdd
}
}
void Peer::tryMemorizedPath(void *tPtr,uint64_t now)
void Peer::tryMemorizedPath(void *tPtr,int64_t now)
{
if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) {
_lastTriedMemorizedPath = now;
@ -379,15 +382,15 @@ void Peer::tryMemorizedPath(void *tPtr,uint64_t now)
}
}
bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily)
bool Peer::doPingAndKeepalive(void *tPtr,int64_t now,int inetAddressFamily)
{
Mutex::Lock _l(_paths_m);
if (inetAddressFamily < 0) {
uint64_t v6lr = 0;
int64_t v6lr = 0;
if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) )
v6lr = _v6Path.p->lastIn();
uint64_t v4lr = 0;
int64_t v4lr = 0;
if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) )
v4lr = _v4Path.p->lastIn();
@ -423,7 +426,7 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily)
return false;
}
void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now)
void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now)
{
if ((remoteAddress.ss_family != AF_INET)&&(remoteAddress.ss_family != AF_INET6)) // sanity check
return;

76
node/Peer.hpp

@ -120,7 +120,7 @@ public:
* @param addr Remote address
* @return True if we have an active path to this destination
*/
inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const
inline bool hasActivePathTo(int64_t now,const InetAddress &addr) const
{
Mutex::Lock _l(_paths_m);
return ( ((addr.ss_family == AF_INET)&&(_v4Path.p)&&(_v4Path.p->address() == addr)&&(_v4Path.p->alive(now))) || ((addr.ss_family == AF_INET6)&&(_v6Path.p)&&(_v6Path.p->address() == addr)&&(_v6Path.p->alive(now))) );
@ -136,7 +136,7 @@ public:
* @param force If true, send even if path is not alive
* @return True if we actually sent something
*/
bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force);
bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force);
/**
* Get the best current direct path
@ -148,7 +148,7 @@ public:
* @param includeExpired If true, include even expired paths
* @return Best current path or NULL if none
*/
SharedPtr<Path> getBestPath(uint64_t now,bool includeExpired);
SharedPtr<Path> getBestPath(int64_t now,bool includeExpired);
/**
* Send a HELLO to this peer at a specified physical address
@ -161,7 +161,7 @@ public:
* @param now Current time
* @param counter Outgoing packet counter
*/
void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter);
void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter);
/**
* Send ECHO (or HELLO for older peers) to this peer at the given address
@ -175,7 +175,7 @@ public:
* @param sendFullHello If true, always send a full HELLO instead of just an ECHO
* @param counter Outgoing packet counter
*/
void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter);
void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello,unsigned int counter);
/**
* Try a memorized or statically defined path if any are known
@ -185,7 +185,7 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param now Current time
*/
void tryMemorizedPath(void *tPtr,uint64_t now);
void tryMemorizedPath(void *tPtr,int64_t now);
/**
* Send pings or keepalives depending on configured timeouts
@ -195,7 +195,7 @@ public:
* @param inetAddressFamily Keep this address family alive, or -1 for any
* @return True if we have at least one direct path of the given family (or any if family is -1)
*/
bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily);
bool doPingAndKeepalive(void *tPtr,int64_t now,int inetAddressFamily);
/**
* Specify remote path for this peer and forget others
@ -209,7 +209,7 @@ public:
* @param remoteAddress Remote address
* @param now Current time
*/
void redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now);
void redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now);
/**
* Reset paths within a given IP scope and address family
@ -222,7 +222,7 @@ public:
* @param inetAddressFamily Family e.g. AF_INET
* @param now Current time
*/
inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now)
inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now)
{
Mutex::Lock _l(_paths_m);
if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) {
@ -243,7 +243,7 @@ public:
* @param v4 Result parameter to receive active IPv4 address, if any
* @param v6 Result parameter to receive active IPv6 address, if any
*/
inline void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
inline void getRendezvousAddresses(int64_t now,InetAddress &v4,InetAddress &v6) const
{
Mutex::Lock _l(_paths_m);
if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now)))
@ -256,7 +256,7 @@ public:
* @param now Current time
* @return All known paths to this peer
*/
inline std::vector< SharedPtr<Path> > paths(const uint64_t now) const
inline std::vector< SharedPtr<Path> > paths(const int64_t now) const
{
std::vector< SharedPtr<Path> > pp;
Mutex::Lock _l(_paths_m);
@ -270,17 +270,17 @@ public:
/**
* @return Time of last receive of anything, whether direct or relayed
*/
inline uint64_t lastReceive() const { return _lastReceive; }
inline int64_t lastReceive() const { return _lastReceive; }
/**
* @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT
*/
inline bool isAlive(const uint64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
inline bool isAlive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
/**
* @return True if this peer has sent us real network traffic recently
*/
inline uint64_t isActive(uint64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
inline int64_t isActive(int64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
/**
* @return Latency in milliseconds or 0 if unknown
@ -298,7 +298,7 @@ public:
*
* @return Relay quality score computed from latency and other factors, lower is better
*/
inline unsigned int relayQuality(const uint64_t now) const
inline unsigned int relayQuality(const int64_t now) const
{
const uint64_t tsr = now - _lastReceive;
if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT)
@ -353,12 +353,12 @@ public:
/**
* @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
*/
inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
/**
* Rate limit gate for VERB_PUSH_DIRECT_PATHS
*/
inline bool rateGatePushDirectPaths(const uint64_t now)
inline bool rateGatePushDirectPaths(const int64_t now)
{
if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME)
++_directPathPushCutoffCount;
@ -370,7 +370,7 @@ public:
/**
* Rate limit gate for VERB_NETWORK_CREDENTIALS
*/
inline bool rateGateCredentialsReceived(const uint64_t now)
inline bool rateGateCredentialsReceived(const int64_t now)
{
if ((now - _lastCredentialsReceived) <= ZT_PEER_CREDENTIALS_CUTOFF_TIME)
++_credentialsCutoffCount;
@ -382,7 +382,7 @@ public:
/**
* Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE
*/
inline bool rateGateRequestCredentials(const uint64_t now)
inline bool rateGateRequestCredentials(const int64_t now)
{
if ((now - _lastCredentialRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) {
_lastCredentialRequestSent = now;
@ -394,7 +394,7 @@ public:
/**
* Rate limit gate for inbound WHOIS requests
*/
inline bool rateGateInboundWhoisRequest(const uint64_t now)
inline bool rateGateInboundWhoisRequest(const int64_t now)
{
if ((now - _lastWhoisRequestReceived) >= ZT_PEER_WHOIS_RATE_LIMIT) {
_lastWhoisRequestReceived = now;
@ -406,7 +406,7 @@ public:
/**
* Rate limit gate for inbound ECHO requests
*/
inline bool rateGateEchoRequest(const uint64_t now)
inline bool rateGateEchoRequest(const int64_t now)
{
if ((now - _lastEchoRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) {
_lastEchoRequestReceived = now;
@ -418,7 +418,7 @@ public:
/**
* Rate gate incoming requests for network COM
*/
inline bool rateGateIncomingComRequest(const uint64_t now)
inline bool rateGateIncomingComRequest(const int64_t now)
{
if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) {
_lastComRequestReceived = now;
@ -430,7 +430,7 @@ public:
/**
* Rate gate outgoing requests for network COM
*/
inline bool rateGateOutgoingComRequest(const uint64_t now)
inline bool rateGateOutgoingComRequest(const int64_t now)
{
if ((now - _lastComRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) {
_lastComRequestSent = now;
@ -484,7 +484,7 @@ public:
}
template<unsigned int C>
inline static SharedPtr<Peer> deserializeFromCache(uint64_t now,void *tPtr,Buffer<C> &b,const RuntimeEnvironment *renv)
inline static SharedPtr<Peer> deserializeFromCache(int64_t now,void *tPtr,Buffer<C> &b,const RuntimeEnvironment *renv)
{
try {
unsigned int ptr = 0;
@ -527,8 +527,8 @@ private:
struct _PeerPath
{
_PeerPath() : lr(0),sticky(0),p() {}
uint64_t lr; // time of last valid ZeroTier packet
uint64_t sticky; // time last set as sticky
int64_t lr; // time of last valid ZeroTier packet
int64_t sticky; // time last set as sticky
SharedPtr<Path> p;
};
@ -536,18 +536,18 @@ private:
const RuntimeEnvironment *RR;
uint64_t _lastReceive; // direct or indirect
uint64_t _lastNontrivialReceive; // frames, things like netconf, etc.
uint64_t _lastTriedMemorizedPath;
uint64_t _lastDirectPathPushSent;
uint64_t _lastDirectPathPushReceive;
uint64_t _lastCredentialRequestSent;
uint64_t _lastWhoisRequestReceived;
uint64_t _lastEchoRequestReceived;
uint64_t _lastComRequestReceived;
uint64_t _lastComRequestSent;
uint64_t _lastCredentialsReceived;
uint64_t _lastTrustEstablishedPacketReceived;
int64_t _lastReceive; // direct or indirect
int64_t _lastNontrivialReceive; // frames, things like netconf, etc.
int64_t _lastTriedMemorizedPath;
int64_t _lastDirectPathPushSent;
int64_t _lastDirectPathPushReceive;
int64_t _lastCredentialRequestSent;
int64_t _lastWhoisRequestReceived;
int64_t _lastEchoRequestReceived;
int64_t _lastComRequestReceived;
int64_t _lastComRequestSent;
int64_t _lastCredentialsReceived;
int64_t _lastTrustEstablishedPacketReceived;
uint16_t _vProto;
uint16_t _vMajor;

4
node/Revocation.hpp

@ -85,7 +85,7 @@ public:
inline uint32_t id() const { return _id; }
inline uint32_t credentialId() const { return _credentialId; }
inline uint64_t networkId() const { return _networkId; }
inline uint64_t threshold() const { return _threshold; }
inline int64_t threshold() const { return _threshold; }
inline const Address &target() const { return _target; }
inline const Address &signer() const { return _signedBy; }
inline Credential::Type type() const { return _type; }
@ -184,7 +184,7 @@ private:
uint32_t _id;
uint32_t _credentialId;
uint64_t _networkId;
uint64_t _threshold;
int64_t _threshold;
uint64_t _flags;
Address _target;
Address _signedBy;

6
node/SelfAwareness.cpp

@ -49,7 +49,7 @@ namespace ZeroTier {
class _ResetWithinScope
{
public:
_ResetWithinScope(void *tPtr,uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) :
_ResetWithinScope(void *tPtr,int64_t now,int inetAddressFamily,InetAddress::IpScope scope) :
_now(now),
_tPtr(tPtr),
_family(inetAddressFamily),
@ -70,7 +70,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
{
}
void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now)
void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now)
{
const InetAddress::IpScope scope = myPhysicalAddress.ipScope();
@ -112,7 +112,7 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
}
}
void SelfAwareness::clean(uint64_t now)
void SelfAwareness::clean(int64_t now)
{
Mutex::Lock _l(_phy_m);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);

4
node/SelfAwareness.hpp

@ -55,14 +55,14 @@ public:
* @param trusted True if this peer is trusted as an authority to inform us of external address changes
* @param now Current time
*/
void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now);
void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now);
/**
* Clean up database periodically
*
* @param now Current time
*/
void clean(uint64_t now);
void clean(int64_t now);
/**
* If we appear to be behind a symmetric NAT, get predictions for possible external endpoints

20
node/Switch.cpp

@ -57,7 +57,7 @@ Switch::Switch(const RuntimeEnvironment *renv) :
void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len)
{
try {
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
const SharedPtr<Path> path(RR->topology->getPath(localSocket,fromAddr));
path->received(now);
@ -557,14 +557,14 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt)
}
}
void Switch::requestWhois(void *tPtr,const uint64_t now,const Address &addr)
void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr)
{
if (addr == RR->identity.address())
return;
{
Mutex::Lock _l(_lastSentWhoisRequest_m);
uint64_t &last = _lastSentWhoisRequest[addr];
int64_t &last = _lastSentWhoisRequest[addr];
if ((now - last) < ZT_WHOIS_RETRY_DELAY)
return;
else last = now;
@ -586,7 +586,7 @@ void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr<Peer> &peer)
_lastSentWhoisRequest.erase(peer->address());
}
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
for(unsigned int ptr=0;ptr<ZT_RX_QUEUE_SIZE;++ptr) {
RXQueueEntry *const rq = &(_rxQueue[ptr]);
if ((rq->timestamp)&&(rq->complete)) {
@ -611,7 +611,7 @@ void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr<Peer> &peer)
}
}
unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now)
unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
{
const uint64_t timeSinceLastCheck = now - _lastCheckedQueues;
if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY)
@ -663,9 +663,9 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now)
{
Mutex::Lock _l(_lastSentWhoisRequest_m);
Hashtable< Address,uint64_t >::Iterator i(_lastSentWhoisRequest);
Hashtable< Address,int64_t >::Iterator i(_lastSentWhoisRequest);
Address *a = (Address *)0;
uint64_t *ts = (uint64_t *)0;
int64_t *ts = (int64_t *)0;
while (i.next(a,ts)) {
if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2))
_lastSentWhoisRequest.erase(*a);
@ -675,7 +675,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now)
return ZT_WHOIS_RETRY_DELAY;
}
bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address &destination)
bool Switch::_shouldUnite(const int64_t now,const Address &source,const Address &destination)
{
Mutex::Lock _l(_lastUniteAttempt_m);
uint64_t &ts = _lastUniteAttempt[_LastUniteKey(source,destination)];
@ -689,7 +689,7 @@ bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address
bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt)
{
SharedPtr<Path> viaPath;
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
const Address destination(packet.destination());
const SharedPtr<Peer> peer(RR->topology->getPeer(tPtr,destination));
@ -703,7 +703,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt)
viaPath = peer->getBestPath(now,false);
if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) {
if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) {
if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(int64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) {
peer->attemptToContactAt(tPtr,viaPath->localSocket(),viaPath->address(),now,false,viaPath->nextOutgoingCounter());
viaPath->sent(now);
}

14
node/Switch.hpp

@ -114,7 +114,7 @@ public:
* @param now Current time
* @param addr Address to look up
*/
void requestWhois(void *tPtr,const uint64_t now,const Address &addr);
void requestWhois(void *tPtr,const int64_t now,const Address &addr);
/**
* Run any processes that are waiting for this peer's identity
@ -136,25 +136,25 @@ public:
* @param now Current time
* @return Number of milliseconds until doTimerTasks() should be run again
*/
unsigned long doTimerTasks(void *tPtr,uint64_t now);
unsigned long doTimerTasks(void *tPtr,int64_t now);
private:
bool _shouldUnite(const uint64_t now,const Address &source,const Address &destination);
bool _shouldUnite(const int64_t now,const Address &source,const Address &destination);
bool _trySend(void *tPtr,Packet &packet,bool encrypt); // packet is modified if return is true
const RuntimeEnvironment *const RR;
uint64_t _lastBeaconResponse;
volatile uint64_t _lastCheckedQueues;
int64_t _lastBeaconResponse;
volatile int64_t _lastCheckedQueues;
// Time we last sent a WHOIS request for each address
Hashtable< Address,uint64_t > _lastSentWhoisRequest;
Hashtable< Address,int64_t > _lastSentWhoisRequest;
Mutex _lastSentWhoisRequest_m;
// Packets waiting for WHOIS replies or other decode info or missing fragments
struct RXQueueEntry
{
RXQueueEntry() : timestamp(0) {}
volatile uint64_t timestamp; // 0 if entry is not in use
volatile int64_t timestamp; // 0 if entry is not in use
volatile uint64_t packetId;
IncomingPacket frag0; // head of packet
Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any)

7
node/Topology.cpp

@ -133,8 +133,9 @@ SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
if (ap)
return ap;
ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR);
if (!ap)
if (!ap) {
_peers.erase(zta);
}
return SharedPtr<Peer>();
}
} catch ( ... ) {} // ignore invalid identities or other strage failures
@ -157,7 +158,7 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta)
SharedPtr<Peer> Topology::getUpstreamPeer()
{
const uint64_t now = RR->node->now();
const int64_t now = RR->node->now();
unsigned int bestq = ~((unsigned int)0);
const SharedPtr<Peer> *best = (const SharedPtr<Peer> *)0;
@ -365,7 +366,7 @@ void Topology::removeMoon(void *tPtr,const uint64_t id)
_memoizeUpstreams(tPtr);
}
void Topology::doPeriodicTasks(void *tPtr,uint64_t now)
void Topology::doPeriodicTasks(void *tPtr,int64_t now)
{
{
Mutex::Lock _l1(_peers_m);

4
node/Topology.hpp

@ -286,13 +286,13 @@ public:
/**
* Clean and flush database
*/
void doPeriodicTasks(void *tPtr,uint64_t now);
void doPeriodicTasks(void *tPtr,int64_t now);
/**
* @param now Current time
* @return Number of peers with active direct paths
*/
inline unsigned long countActive(uint64_t now) const
inline unsigned long countActive(int64_t now) const
{
unsigned long cnt = 0;
Mutex::Lock _l(_peers_m);

6
one.cpp

@ -364,9 +364,9 @@ static int cli(int argc,char **argv)
if (path["preferred"]) {
char tmp[256];
std::string addr = path["address"];
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
const double lq = (path.count("linkQuality")) ? (double)path["linkQuality"] : -1.0;
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s;%llu;%llu;%1.2f",addr.c_str(),now - (uint64_t)path["lastSend"],now - (uint64_t)path["lastReceive"],lq);
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s;%lld;%lld;%1.2f",addr.c_str(),now - (int64_t)path["lastSend"],now - (int64_t)path["lastReceive"],lq);
bestPath = tmp;
break;
}
@ -864,7 +864,7 @@ static int idtool(int argc,char **argv)
}
std::sort(roots.begin(),roots.end());
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
World w(World::make(t,id,now,updatesMustBeSignedBy,roots,signingKey));
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> wbuf;
w.serialize(wbuf);

6
osdep/OSUtils.hpp

@ -200,7 +200,7 @@ public:
/**
* @return Current time in milliseconds since epoch
*/
static inline uint64_t now()
static inline int64_t now()
{
#ifdef __WINDOWS__
FILETIME ft;
@ -210,7 +210,7 @@ public:
SystemTimeToFileTime(&st,&ft);
tmp.LowPart = ft.dwLowDateTime;
tmp.HighPart = ft.dwHighDateTime;
return ( ((tmp.QuadPart - 116444736000000000ULL) / 10000L) + st.wMilliseconds );
return (int64_t)( ((tmp.QuadPart - 116444736000000000LL) / 10000L) + st.wMilliseconds );
#else
struct timeval tv;
#ifdef __LINUX__
@ -218,7 +218,7 @@ public:
#else
gettimeofday(&tv,(struct timezone *)0);
#endif
return ( (1000ULL * (uint64_t)tv.tv_sec) + (uint64_t)(tv.tv_usec / 1000) );
return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) );
#endif
};

2
osdep/PortMapper.cpp

@ -131,7 +131,7 @@ public:
InetAddress publicAddress;
sendpublicaddressrequest(&natpmp);
uint64_t myTimeout = OSUtils::now() + 5000;
int64_t myTimeout = OSUtils::now() + 5000;
do {
fd_set fds;
struct timeval timeout;

22
service/OneService.cpp

@ -276,6 +276,10 @@ static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer)
pa.push_back(j);
}
pj["paths"] = pa;
if (peer->address == 0xda6c71a1ad) {
fprintf(stdout, "%s\n", pj.dump(2).c_str());
}
}
static void _moonToJson(nlohmann::json &mj,const World &world)
@ -436,7 +440,7 @@ public:
uint64_t _lastRestart;
// Deadline for the next background task service function
volatile uint64_t _nextBackgroundTaskDeadline;
volatile int64_t _nextBackgroundTaskDeadline;
// Configured networks
struct NetworkState
@ -755,12 +759,12 @@ public:
// Main I/O loop
_nextBackgroundTaskDeadline = 0;
uint64_t clockShouldBe = OSUtils::now();
int64_t clockShouldBe = OSUtils::now();
_lastRestart = clockShouldBe;
uint64_t lastTapMulticastGroupCheck = 0;
uint64_t lastBindRefresh = 0;
uint64_t lastUpdateCheck = clockShouldBe;
uint64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle
int64_t lastTapMulticastGroupCheck = 0;
int64_t lastBindRefresh = 0;
int64_t lastUpdateCheck = clockShouldBe;
int64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle
for(;;) {
_run_m.lock();
if (!_run) {
@ -773,7 +777,7 @@ public:
_run_m.unlock();
}
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
// Attempt to detect sleep/wake events by detecting delay overruns
bool restarted = false;
@ -809,7 +813,7 @@ public:
}
// Run background task processor in core if it's time to do so
uint64_t dl = _nextBackgroundTaskDeadline;
int64_t dl = _nextBackgroundTaskDeadline;
if (dl <= now) {
_node->processBackgroundTasks((void *)0,now,&_nextBackgroundTaskDeadline);
dl = _nextBackgroundTaskDeadline;
@ -2152,7 +2156,7 @@ public:
// Engage TCP tunnel fallback if we haven't received anything valid from a global
// IP address in ZT_TCP_FALLBACK_AFTER milliseconds. If we do start getting
// valid direct traffic we'll stop using it and close the socket after a while.
const uint64_t now = OSUtils::now();
const int64_t now = OSUtils::now();
if (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER)&&((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER)) {
if (_tcpFallbackTunnel) {
bool flushNow = false;

2
service/SoftwareUpdater.cpp

@ -303,7 +303,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void
}
}
bool SoftwareUpdater::check(const uint64_t now)
bool SoftwareUpdater::check(const int64_t now)
{
if ((now - _lastCheckTime) >= ZT_SOFTWARE_UPDATE_CHECK_PERIOD) {
_lastCheckTime = now;

2
service/SoftwareUpdater.hpp

@ -167,7 +167,7 @@ public:
*
* @return True if we've downloaded and verified an update
*/
bool check(const uint64_t now);
bool check(const int64_t now);
/**
* @return Meta-data for downloaded update or NULL if none

Loading…
Cancel
Save