Continuing work on new buffer type...

This commit is contained in:
Adam Ierymenko 2020-01-25 01:17:56 -08:00
parent 59da359b06
commit d5b9a54c55
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
13 changed files with 263 additions and 191 deletions

View file

@ -70,10 +70,12 @@ set(core_src
Peer.cpp
Poly1305.cpp
Protocol.cpp
Revocation.cpp
Salsa20.cpp
SelfAwareness.cpp
SHA512.cpp
Switch.cpp
Tag.cpp
Topology.cpp
Trace.cpp
Utils.cpp

View file

@ -122,7 +122,7 @@ int Capability::unmarshal(const uint8_t *data,int len)
return p;
}
int Capability::marshalVirtualNetworkRules(uint8_t data[ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX],const ZT_VirtualNetworkRule *const rules,const unsigned int ruleCount)
int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetworkRule *const rules,const unsigned int ruleCount)
{
int p = 0;
for(unsigned int i=0;i<ruleCount;++i) {

View file

@ -159,7 +159,7 @@ public:
int marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX],bool forSign = false) const;
int unmarshal(const uint8_t *data,int len);
static int marshalVirtualNetworkRules(uint8_t data[ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX],const ZT_VirtualNetworkRule *rules,unsigned int ruleCount);
static int marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount);
static int unmarshalVirtualNetworkRules(const uint8_t *data,int len,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,unsigned int maxRuleCount);
// Provides natural sort order by ID

View file

@ -233,10 +233,6 @@
// Exceptions thrown in core ZT code
#define ZT_EXCEPTION_OUT_OF_BOUNDS 100
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE 200
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW 201
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN 202
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING 203
/* Ethernet frame types that might be relevant to us */
#define ZT_ETHERTYPE_IPV4 0x0800

View file

@ -313,7 +313,7 @@ bool InetAddress::isNetwork() const
return false;
}
int InetAddress::marshal(uint8_t data[19]) const
int InetAddress::marshal(uint8_t data[ZT_INETADDRESS_MARSHAL_SIZE_MAX]) const
{
unsigned int port;
switch(ss_family) {

View file

@ -494,7 +494,7 @@ public:
explicit ZT_ALWAYS_INLINE operator bool() const { return (ss_family != 0); }
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_INETADDRESS_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[19]) const;
int marshal(uint8_t data[ZT_INETADDRESS_MARSHAL_SIZE_MAX]) const;
int unmarshal(const uint8_t *restrict data,const int len);
bool operator==(const InetAddress &a) const;

View file

@ -43,7 +43,8 @@ NetworkConfig::NetworkConfig() :
bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const
{
ScopedPtr< Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> > tmp(new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>());
uint8_t tmp[16384];
std::vector<uint8_t> buf;
char tmp2[128];
d.clear();
@ -64,62 +65,90 @@ bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const
// Then add binary blobs
if (this->com) {
tmp->clear();
this->com.serialize(*tmp);
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,(const char *)tmp,this->com.marshal(tmp)))
return false;
}
tmp->clear();
for(unsigned int i=0;i<this->capabilityCount;++i)
this->capabilities[i].serialize(*tmp);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) return false;
buf.clear();
for(unsigned int i=0;i<this->capabilityCount;++i) {
int l = this->capabilities[i].marshal(tmp);
if (l < 0)
return false;
buf.insert(buf.end(),tmp,tmp + l);
}
if (!buf.empty()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,(const char *)buf.data(),(int)buf.size()))
return false;
}
tmp->clear();
for(unsigned int i=0;i<this->tagCount;++i)
this->tags[i].serialize(*tmp);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) return false;
buf.clear();
for(unsigned int i=0;i<this->tagCount;++i) {
int l = this->tags[i].marshal(tmp);
if (l < 0)
return false;
buf.insert(buf.end(),tmp,tmp + l);
}
if (!buf.empty()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,(const char *)buf.data(),(int)buf.size()))
return false;
}
tmp->clear();
for(unsigned int i=0;i<this->certificateOfOwnershipCount;++i)
this->certificatesOfOwnership[i].serialize(*tmp);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) return false;
buf.clear();
for(unsigned int i=0;i<this->certificateOfOwnershipCount;++i) {
int l = this->certificatesOfOwnership[i].marshal(tmp);
if (l < 0)
return false;
buf.insert(buf.end(),tmp,tmp + l);
}
if (!buf.empty()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,(const char *)buf.data(),(int)buf.size()))
return false;
}
tmp->clear();
for(unsigned int i=0;i<this->specialistCount;++i)
tmp->append((uint64_t)this->specialists[i]);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) return false;
buf.clear();
for(unsigned int i=0;i<this->specialistCount;++i) {
Utils::storeBigEndian<uint64_t>(tmp,this->specialists[i]);
buf.insert(buf.end(),tmp,tmp + 8);
}
if (!buf.empty()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,(const char *)buf.data(),(int)buf.size()))
return false;
}
tmp->clear();
buf.clear();
for(unsigned int i=0;i<this->routeCount;++i) {
reinterpret_cast<const InetAddress *>(&(this->routes[i].target))->serialize(*tmp);
reinterpret_cast<const InetAddress *>(&(this->routes[i].via))->serialize(*tmp);
tmp->append((uint16_t)this->routes[i].flags);
tmp->append((uint16_t)this->routes[i].metric);
int l = asInetAddress(this->routes[i].target).marshal(tmp);
if (l < 0)
return false;
buf.insert(buf.end(),tmp,tmp + l);
l = asInetAddress(this->routes[i].via).marshal(tmp);
if (l < 0)
return false;
buf.insert(buf.end(),tmp,tmp + l);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) return false;
if (!buf.empty()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,(const char *)buf.data(),(int)buf.size()))
return false;
}
tmp->clear();
for(unsigned int i=0;i<this->staticIpCount;++i)
this->staticIps[i].serialize(*tmp);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) return false;
buf.clear();
for(unsigned int i=0;i<this->staticIpCount;++i) {
int l = this->staticIps[i].marshal(tmp);
if (l < 0)
return false;
buf.insert(buf.end(),tmp,tmp + l);
}
if (!buf.empty()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,(const char *)buf.data(),(int)buf.size()))
return false;
}
if (this->ruleCount) {
tmp->clear();
Capability::serializeRules(*tmp,rules,ruleCount);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) return false;
buf.resize(ruleCount * ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX);
int l = Capability::marshalVirtualNetworkRules(buf.data(),rules,ruleCount);
if (l > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,(const char *)buf.data(),l))
return false;
}
}

View file

@ -27,7 +27,7 @@ namespace Protocol {
namespace {
const uint8_t ZEROES32[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
const uint64_t ZEROES32[4] = { 0,0,0,0 };
/**
* Deterministically mangle a 256-bit crypto key based on packet

89
node/Revocation.cpp Normal file
View file

@ -0,0 +1,89 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#include "Revocation.hpp"
namespace ZeroTier {
bool Revocation::sign(const Identity &signer)
{
uint8_t buf[ZT_REVOCATION_MARSHAL_SIZE_MAX+32];
if (signer.hasPrivate()) {
_signedBy = signer.address();
_signatureLength = signer.sign(buf,(unsigned int)marshal(buf,true),_signature,sizeof(_signature));
return true;
}
return false;
}
int Revocation::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX],bool forSign) const
{
int p = 0;
if (forSign) {
for(int k=0;k<8;++k)
data[p++] = 0x7f;
}
Utils::storeBigEndian<uint32_t>(data + p,0); p += 4;
Utils::storeBigEndian<uint32_t>(data + p,_id); p += 4;
Utils::storeBigEndian<uint64_t>(data + p,_networkId); p += 8;
Utils::storeBigEndian<uint32_t>(data + p,0); p += 4;
Utils::storeBigEndian<uint32_t>(data + p,_credentialId); p += 4;
Utils::storeBigEndian<uint64_t>(data + p,(uint64_t)_threshold); p += 8;
Utils::storeBigEndian<uint64_t>(data + p,_flags); p += 8;
_target.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
_signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
data[p++] = (uint8_t)_type;
if (!forSign) {
data[p++] = 1;
Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength);
memcpy(data + p,_signature,_signatureLength);
p += (int)_signatureLength;
}
data[p++] = 0;
data[p++] = 0;
if (forSign) {
for(int k=0;k<8;++k)
data[p++] = 0x7f;
}
return p;
}
int Revocation::unmarshal(const uint8_t *restrict data,const int len)
{
if (len < 54)
return -1;
// 4 bytes reserved
_id = Utils::loadBigEndian<uint32_t>(data + 4);
_networkId = Utils::loadBigEndian<uint64_t>(data + 8);
// 4 bytes reserved
_credentialId = Utils::loadBigEndian<uint32_t>(data + 20);
_threshold = (int64_t)Utils::loadBigEndian<uint64_t>(data + 24);
_flags = Utils::loadBigEndian<uint64_t>(data + 32);
_target.setTo(data + 40);
_signedBy.setTo(data + 45);
_type = (ZT_CredentialType)data[50];
// 1 byte reserved
_signatureLength = Utils::loadBigEndian<uint16_t>(data + 52);
int p = 54 + (int)_signatureLength;
if ((_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)||(p > len))
return -1;
memcpy(_signature,data + 54,_signatureLength);
if ((p + 2) > len)
return -1;
p += 2 + Utils::loadBigEndian<uint16_t>(data + p);
if (p > len)
return -1;
return p;
}
} // namespace ZeroTier

View file

@ -31,6 +31,8 @@
*/
#define ZT_REVOCATION_FLAG_FAST_PROPAGATE 0x1ULL
#define ZT_REVOCATION_MARSHAL_SIZE_MAX (4 + 4 + 8 + 4 + 4 + 8 + 8 + 5 + 5 + 1 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2)
namespace ZeroTier {
class RuntimeEnvironment;
@ -95,17 +97,7 @@ public:
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
ZT_ALWAYS_INLINE bool sign(const Identity &signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(Revocation) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
return true;
}
return false;
}
bool sign(const Identity &signer);
/**
* Verify this revocation's signature
@ -115,67 +107,9 @@ public:
*/
ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append(_id);
b.append(_networkId);
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append(_credentialId);
b.append(_threshold);
b.append(_flags);
_target.appendTo(b);
_signedBy.appendTo(b);
b.append((uint8_t)_type);
if (!forSign) {
b.append((uint8_t)1);
b.append((uint16_t)_signatureLength);
b.append(_signature,_signatureLength);
}
// This is the size of any additional fields, currently 0.
b.append((uint16_t)0);
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
*this = Revocation();
unsigned int p = startAt;
p += 4; // 4 bytes, currently unused
_id = b.template at<uint32_t>(p); p += 4;
_networkId = b.template at<uint64_t>(p); p += 8;
p += 4; // 4 bytes, currently unused
_credentialId = b.template at<uint32_t>(p); p += 4;
_threshold = b.template at<uint64_t>(p); p += 8;
_flags = b.template at<uint64_t>(p); p += 8;
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_type = (ZT_CredentialType)b[p++];
if (b[p++] == 1) {
_signatureLength = b.template at<uint16_t>(p);
if (_signatureLength > sizeof(_signature))
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
memcpy(_signature,b.field(p,_signatureLength),_signatureLength);
} else {
p += 2 + b.template at<uint16_t>(p);
}
p += 2 + b.template at<uint16_t>(p);
if (p > b.size())
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
return (p - startAt);
}
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_REVOCATION_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX],bool forSign = false) const;
int unmarshal(const uint8_t *restrict data,const int len);
private:
uint32_t _id;

81
node/Tag.cpp Normal file
View file

@ -0,0 +1,81 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#include "Tag.hpp"
namespace ZeroTier {
bool Tag::sign(const Identity &signer)
{
uint8_t buf[ZT_TAG_MARSHAL_SIZE_MAX];
if (signer.hasPrivate()) {
_signedBy = signer.address();
_signatureLength = signer.sign(buf,(unsigned int)marshal(buf,true),_signature,sizeof(_signature));
return true;
}
return false;
}
int Tag::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX],bool forSign) const
{
int p = 0;
if (forSign) {
for(int k=0;k<8;++k)
data[p++] = 0x7f;
}
Utils::storeBigEndian<uint64_t>(data + p,_networkId); p += 8;
Utils::storeBigEndian<uint64_t>(data + p,(uint64_t)_ts); p += 8;
Utils::storeBigEndian<uint32_t>(data + p,_id); p += 4;
Utils::storeBigEndian<uint32_t>(data + p,_value); p += 4;
_issuedTo.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
_signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
if (!forSign) {
data[p++] = 1;
Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength); p += 2;
memcpy(data + p,_signature,_signatureLength);
p += (int)_signatureLength;
}
data[p++] = 0;
data[p++] = 0;
if (forSign) {
for(int k=0;k<8;++k)
data[p++] = 0x7f;
}
return p;
}
int Tag::unmarshal(const uint8_t *data,int len)
{
if (len < 37)
return -1;
_networkId = Utils::loadBigEndian<uint64_t>(data);
_ts = (int64_t)Utils::loadBigEndian<uint64_t>(data + 8);
_id = Utils::loadBigEndian<uint32_t>(data + 16);
_value = Utils::loadBigEndian<uint32_t>(data + 20);
_issuedTo.setTo(data + 24);
_signedBy.setTo(data + 29);
// 1 byte reserved
_signatureLength = Utils::loadBigEndian<uint16_t>(data + 35);
int p = 37 + (int)_signatureLength;
if ((_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)||(p > len))
return -1;
memcpy(_signature,data + p,_signatureLength);
if ((p + 2) > len)
return -1;
p += 2 + Utils::loadBigEndian<uint16_t>(data + p);
if (p > len)
return -1;
return p;
}
} // namespace ZeroTier

View file

@ -25,6 +25,8 @@
#include "Address.hpp"
#include "Identity.hpp"
#define ZT_TAG_MARSHAL_SIZE_MAX (8 + 8 + 4 + 4 + 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2)
namespace ZeroTier {
class RuntimeEnvironment;
@ -95,17 +97,7 @@ public:
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
inline bool sign(const Identity &signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(Tag) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
return true;
}
return false;
}
bool sign(const Identity &signer);
/**
* Check this tag's signature
@ -115,60 +107,9 @@ public:
*/
ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
b.append(_networkId);
b.append(_ts);
b.append(_id);
b.append(_value);
_issuedTo.appendTo(b);
_signedBy.appendTo(b);
if (!forSign) {
b.append((uint8_t)1);
b.append((uint16_t)_signatureLength);
b.append(_signature,_signatureLength);
}
b.append((uint16_t)0); // length of additional fields, currently 0
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
unsigned int p = startAt;
*this = Tag();
_networkId = b.template at<uint64_t>(p); p += 8;
_ts = b.template at<uint64_t>(p); p += 8;
_id = b.template at<uint32_t>(p); p += 4;
_value = b.template at<uint32_t>(p); p += 4;
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
_signatureLength = b.template at<uint16_t>(p);
if (_signatureLength > sizeof(_signature))
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
p += 2;
memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength;
} else {
p += 2 + b.template at<uint16_t>(p);
}
p += 2 + b.template at<uint16_t>(p);
if (p > b.size())
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
return (p - startAt);
}
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_TAG_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX],bool forSign = false) const;
int unmarshal(const uint8_t *data,int len);
// Provides natural sort order by ID
ZT_ALWAYS_INLINE bool operator<(const Tag &t) const { return (_id < t._id); }

View file

@ -212,14 +212,14 @@ static ZT_ALWAYS_INLINE unsigned long hexStrToULong(const char *s) { return strt
static ZT_ALWAYS_INLINE long hexStrToLong(const char *s) { return strtol(s,(char **)0,16); }
#endif
static ZT_ALWAYS_INLINE unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,10); }
static ZT_ALWAYS_INLINE unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,nullptr,10); }
static ZT_ALWAYS_INLINE unsigned long long strToU64(const char *s)
{
#ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,(char **)0,10);
#else
return strtoull(s,(char **)0,10);
return strtoull(s,nullptr,10);
#endif
}
@ -228,16 +228,16 @@ static ZT_ALWAYS_INLINE long long hexStrTo64(const char *s)
#ifdef __WINDOWS__
return (long long)_strtoi64(s,(char **)0,16);
#else
return strtoll(s,(char **)0,16);
return strtoll(s,nullptr,16);
#endif
}
static ZT_ALWAYS_INLINE unsigned long long hexStrToU64(const char *s)
{
#ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,(char **)0,16);
return (unsigned long long)_strtoui64(s,nullptr,16);
#else
return strtoull(s,(char **)0,16);
return strtoull(s,nullptr,16);
#endif
}