summaryrefslogtreecommitdiff
path: root/node/Utils.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'node/Utils.hpp')
-rw-r--r--node/Utils.hpp387
1 files changed, 236 insertions, 151 deletions
diff --git a/node/Utils.hpp b/node/Utils.hpp
index ceb29d7e..a24f2c9a 100644
--- a/node/Utils.hpp
+++ b/node/Utils.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_UTILS_HPP
@@ -32,6 +40,44 @@
#include "Constants.hpp"
+#ifdef __LINUX__
+//#if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
+#if 0
+#include <emmintrin.h>
+static inline void ZT_FAST_MEMCPY(void *a,const void *b,unsigned long k)
+{
+ char *aa = reinterpret_cast<char *>(a);
+ const char *bb = reinterpret_cast<const char *>(b);
+ while (k >= 64) {
+ __m128 t1 = _mm_loadu_ps(reinterpret_cast<const float *>(bb));
+ __m128 t2 = _mm_loadu_ps(reinterpret_cast<const float *>(bb + 16));
+ __m128 t3 = _mm_loadu_ps(reinterpret_cast<const float *>(bb + 32));
+ __m128 t4 = _mm_loadu_ps(reinterpret_cast<const float *>(bb + 48));
+ _mm_storeu_ps(reinterpret_cast<float *>(aa),t1);
+ _mm_storeu_ps(reinterpret_cast<float *>(aa + 16),t2);
+ _mm_storeu_ps(reinterpret_cast<float *>(aa + 32),t3);
+ _mm_storeu_ps(reinterpret_cast<float *>(aa + 48),t4);
+ bb += 64;
+ aa += 64;
+ k -= 64;
+ }
+ while (k >= 16) {
+ __m128 t1 = _mm_loadu_ps(reinterpret_cast<const float *>(bb));
+ _mm_storeu_ps(reinterpret_cast<float *>(aa),t1);
+ bb += 16;
+ aa += 16;
+ k -= 16;
+ }
+ for(unsigned long i=0;i<k;++i)
+ aa[i] = bb[i];
+}
+#else
+#define ZT_FAST_MEMCPY(a,b,c) memcpy(a,b,c)
+#endif
+#else
+#define ZT_FAST_MEMCPY(a,b,c) memcpy(a,b,c)
+#endif
+
namespace ZeroTier {
/**
@@ -62,42 +108,158 @@ public:
static void burn(void *ptr,unsigned int len);
/**
- * Convert binary data to hexadecimal
- *
- * @param data Data to convert to hex
- * @param len Length of data
- * @return Hexadecimal string
+ * @param n Number to convert
+ * @param s Buffer, at least 24 bytes in size
+ * @return String containing 'n' in base 10 form
*/
- static std::string hex(const void *data,unsigned int len);
- static inline std::string hex(const std::string &data) { return hex(data.data(),(unsigned int)data.length()); }
+ static char *decimal(unsigned long n,char s[24]);
- /**
- * Convert hexadecimal to binary data
- *
- * This ignores all non-hex characters, just stepping over them and
- * continuing. Upper and lower case are supported for letters a-f.
- *
- * @param hex Hexadecimal ASCII code (non-hex chars are ignored, stops at zero or maxlen)
- * @param maxlen Maximum length of hex string buffer
- * @return Binary data
- */
- static std::string unhex(const char *hex,unsigned int maxlen);
- static inline std::string unhex(const std::string &hex) { return unhex(hex.c_str(),(unsigned int)hex.length()); }
+ static inline char *hex(uint64_t i,char s[17])
+ {
+ s[0] = HEXCHARS[(i >> 60) & 0xf];
+ s[1] = HEXCHARS[(i >> 56) & 0xf];
+ s[2] = HEXCHARS[(i >> 52) & 0xf];
+ s[3] = HEXCHARS[(i >> 48) & 0xf];
+ s[4] = HEXCHARS[(i >> 44) & 0xf];
+ s[5] = HEXCHARS[(i >> 40) & 0xf];
+ s[6] = HEXCHARS[(i >> 36) & 0xf];
+ s[7] = HEXCHARS[(i >> 32) & 0xf];
+ s[8] = HEXCHARS[(i >> 28) & 0xf];
+ s[9] = HEXCHARS[(i >> 24) & 0xf];
+ s[10] = HEXCHARS[(i >> 20) & 0xf];
+ s[11] = HEXCHARS[(i >> 16) & 0xf];
+ s[12] = HEXCHARS[(i >> 12) & 0xf];
+ s[13] = HEXCHARS[(i >> 8) & 0xf];
+ s[14] = HEXCHARS[(i >> 4) & 0xf];
+ s[15] = HEXCHARS[i & 0xf];
+ s[16] = (char)0;
+ return s;
+ }
- /**
- * Convert hexadecimal to binary data
- *
- * This ignores all non-hex characters, just stepping over them and
- * continuing. Upper and lower case are supported for letters a-f.
- *
- * @param hex Hexadecimal ASCII
- * @param maxlen Maximum length of hex string buffer
- * @param buf Buffer to fill
- * @param len Length of buffer
- * @return Number of characters actually written
- */
- static unsigned int unhex(const char *hex,unsigned int maxlen,void *buf,unsigned int len);
- static inline unsigned int unhex(const std::string &hex,void *buf,unsigned int len) { return unhex(hex.c_str(),(unsigned int)hex.length(),buf,len); }
+ static inline char *hex10(uint64_t i,char s[11])
+ {
+ s[0] = HEXCHARS[(i >> 36) & 0xf];
+ s[1] = HEXCHARS[(i >> 32) & 0xf];
+ s[2] = HEXCHARS[(i >> 28) & 0xf];
+ s[3] = HEXCHARS[(i >> 24) & 0xf];
+ s[4] = HEXCHARS[(i >> 20) & 0xf];
+ s[5] = HEXCHARS[(i >> 16) & 0xf];
+ s[6] = HEXCHARS[(i >> 12) & 0xf];
+ s[7] = HEXCHARS[(i >> 8) & 0xf];
+ s[8] = HEXCHARS[(i >> 4) & 0xf];
+ s[9] = HEXCHARS[i & 0xf];
+ s[10] = (char)0;
+ return s;
+ }
+
+ static inline char *hex(uint32_t i,char s[9])
+ {
+ s[0] = HEXCHARS[(i >> 28) & 0xf];
+ s[1] = HEXCHARS[(i >> 24) & 0xf];
+ s[2] = HEXCHARS[(i >> 20) & 0xf];
+ s[3] = HEXCHARS[(i >> 16) & 0xf];
+ s[4] = HEXCHARS[(i >> 12) & 0xf];
+ s[5] = HEXCHARS[(i >> 8) & 0xf];
+ s[6] = HEXCHARS[(i >> 4) & 0xf];
+ s[7] = HEXCHARS[i & 0xf];
+ s[8] = (char)0;
+ return s;
+ }
+
+ static inline char *hex(uint16_t i,char s[5])
+ {
+ s[0] = HEXCHARS[(i >> 12) & 0xf];
+ s[1] = HEXCHARS[(i >> 8) & 0xf];
+ s[2] = HEXCHARS[(i >> 4) & 0xf];
+ s[3] = HEXCHARS[i & 0xf];
+ s[4] = (char)0;
+ return s;
+ }
+
+ static inline char *hex(uint8_t i,char s[3])
+ {
+ s[0] = HEXCHARS[(i >> 4) & 0xf];
+ s[1] = HEXCHARS[i & 0xf];
+ s[2] = (char)0;
+ return s;
+ }
+
+ static inline char *hex(const void *d,unsigned int l,char *s)
+ {
+ char *const save = s;
+ for(unsigned int i=0;i<l;++i) {
+ const unsigned int b = reinterpret_cast<const uint8_t *>(d)[i];
+ *(s++) = HEXCHARS[b >> 4];
+ *(s++) = HEXCHARS[b & 0xf];
+ }
+ *s = (char)0;
+ return save;
+ }
+
+ static inline unsigned int unhex(const char *h,void *buf,unsigned int buflen)
+ {
+ unsigned int l = 0;
+ while (l < buflen) {
+ uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
+ if (!hc) break;
+
+ uint8_t c = 0;
+ if ((hc >= 48)&&(hc <= 57)) // 0..9
+ c = hc - 48;
+ else if ((hc >= 97)&&(hc <= 102)) // a..f
+ c = hc - 87;
+ else if ((hc >= 65)&&(hc <= 70)) // A..F
+ c = hc - 55;
+
+ hc = *(reinterpret_cast<const uint8_t *>(h++));
+ if (!hc) break;
+
+ c <<= 4;
+ if ((hc >= 48)&&(hc <= 57))
+ c |= hc - 48;
+ else if ((hc >= 97)&&(hc <= 102))
+ c |= hc - 87;
+ else if ((hc >= 65)&&(hc <= 70))
+ c |= hc - 55;
+
+ reinterpret_cast<uint8_t *>(buf)[l++] = c;
+ }
+ return l;
+ }
+
+ static inline unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen)
+ {
+ unsigned int l = 0;
+ const char *hend = h + hlen;
+ while (l < buflen) {
+ if (h == hend) break;
+ uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
+ if (!hc) break;
+
+ uint8_t c = 0;
+ if ((hc >= 48)&&(hc <= 57))
+ c = hc - 48;
+ else if ((hc >= 97)&&(hc <= 102))
+ c = hc - 87;
+ else if ((hc >= 65)&&(hc <= 70))
+ c = hc - 55;
+
+ if (h == hend) break;
+ hc = *(reinterpret_cast<const uint8_t *>(h++));
+ if (!hc) break;
+
+ c <<= 4;
+ if ((hc >= 48)&&(hc <= 57))
+ c |= hc - 48;
+ else if ((hc >= 97)&&(hc <= 102))
+ c |= hc - 87;
+ else if ((hc >= 65)&&(hc <= 70))
+ c |= hc - 55;
+
+ reinterpret_cast<uint8_t *>(buf)[l++] = c;
+ }
+ return l;
+ }
/**
* Generate secure random bytes
@@ -118,7 +280,6 @@ public:
* @param saveptr Pointer to a char * for temporary reentrant storage
*/
static inline char *stok(char *str,const char *delim,char **saveptr)
- throw()
{
#ifdef __WINDOWS__
return strtok_s(str,delim,saveptr);
@@ -127,30 +288,11 @@ public:
#endif
}
- // String to number converters -- defined here to permit portability
- // ifdefs for platforms that lack some of the strtoXX functions.
- static inline unsigned int strToUInt(const char *s)
- throw()
- {
- return (unsigned int)strtoul(s,(char **)0,10);
- }
- static inline int strToInt(const char *s)
- throw()
- {
- return (int)strtol(s,(char **)0,10);
- }
- static inline unsigned long strToULong(const char *s)
- throw()
- {
- return strtoul(s,(char **)0,10);
- }
- static inline long strToLong(const char *s)
- throw()
- {
- return strtol(s,(char **)0,10);
- }
+ static inline unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,10); }
+ static inline int strToInt(const char *s) { return (int)strtol(s,(char **)0,10); }
+ static inline unsigned long strToULong(const char *s) { return strtoul(s,(char **)0,10); }
+ static inline long strToLong(const char *s) { return strtol(s,(char **)0,10); }
static inline unsigned long long strToU64(const char *s)
- throw()
{
#ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,(char **)0,10);
@@ -159,7 +301,6 @@ public:
#endif
}
static inline long long strTo64(const char *s)
- throw()
{
#ifdef __WINDOWS__
return (long long)_strtoi64(s,(char **)0,10);
@@ -167,28 +308,11 @@ public:
return strtoll(s,(char **)0,10);
#endif
}
- static inline unsigned int hexStrToUInt(const char *s)
- throw()
- {
- return (unsigned int)strtoul(s,(char **)0,16);
- }
- static inline int hexStrToInt(const char *s)
- throw()
- {
- return (int)strtol(s,(char **)0,16);
- }
- static inline unsigned long hexStrToULong(const char *s)
- throw()
- {
- return strtoul(s,(char **)0,16);
- }
- static inline long hexStrToLong(const char *s)
- throw()
- {
- return strtol(s,(char **)0,16);
- }
+ static inline unsigned int hexStrToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,16); }
+ static inline int hexStrToInt(const char *s) { return (int)strtol(s,(char **)0,16); }
+ static inline unsigned long hexStrToULong(const char *s) { return strtoul(s,(char **)0,16); }
+ static inline long hexStrToLong(const char *s) { return strtol(s,(char **)0,16); }
static inline unsigned long long hexStrToU64(const char *s)
- throw()
{
#ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,(char **)0,16);
@@ -197,7 +321,6 @@ public:
#endif
}
static inline long long hexStrTo64(const char *s)
- throw()
{
#ifdef __WINDOWS__
return (long long)_strtoi64(s,(char **)0,16);
@@ -205,11 +328,6 @@ public:
return strtoll(s,(char **)0,16);
#endif
}
- static inline double strToDouble(const char *s)
- throw()
- {
- return strtod(s,(char **)0);
- }
/**
* Perform a safe C string copy, ALWAYS null-terminating the result
@@ -222,22 +340,23 @@ public:
* @param src Source string (if NULL, dest will receive a zero-length string and true is returned)
* @return True on success, false on overflow (buffer will still be 0-terminated)
*/
- static bool scopy(char *dest,unsigned int len,const char *src);
-
- /**
- * Variant of snprintf that is portable and throws an exception
- *
- * This just wraps the local implementation whatever it's called, while
- * performing a few other checks and adding exceptions for overflow.
- *
- * @param buf Buffer to write to
- * @param len Length of buffer in bytes
- * @param fmt Format string
- * @param ... Format arguments
- * @throws std::length_error buf[] too short (buf[] will still be left null-terminated)
- */
- static unsigned int snprintf(char *buf,unsigned int len,const char *fmt,...)
- throw(std::length_error);
+ static inline bool scopy(char *dest,unsigned int len,const char *src)
+ {
+ if (!len)
+ return false; // sanity check
+ if (!src) {
+ *dest = (char)0;
+ return true;
+ }
+ char *end = dest + len;
+ while ((*dest++ = *src++)) {
+ if (dest == end) {
+ *(--dest) = (char)0;
+ return false;
+ }
+ }
+ return true;
+ }
/**
* Count the number of bits set in an integer
@@ -283,14 +402,13 @@ public:
}
// Byte swappers for big/little endian conversion
- static inline uint8_t hton(uint8_t n) throw() { return n; }
- static inline int8_t hton(int8_t n) throw() { return n; }
- static inline uint16_t hton(uint16_t n) throw() { return htons(n); }
- static inline int16_t hton(int16_t n) throw() { return (int16_t)htons((uint16_t)n); }
- static inline uint32_t hton(uint32_t n) throw() { return htonl(n); }
- static inline int32_t hton(int32_t n) throw() { return (int32_t)htonl((uint32_t)n); }
+ static inline uint8_t hton(uint8_t n) { return n; }
+ static inline int8_t hton(int8_t n) { return n; }
+ static inline uint16_t hton(uint16_t n) { return htons(n); }
+ static inline int16_t hton(int16_t n) { return (int16_t)htons((uint16_t)n); }
+ static inline uint32_t hton(uint32_t n) { return htonl(n); }
+ static inline int32_t hton(int32_t n) { return (int32_t)htonl((uint32_t)n); }
static inline uint64_t hton(uint64_t n)
- throw()
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
#if defined(__GNUC__) && (!defined(__OpenBSD__))
@@ -311,16 +429,15 @@ public:
return n;
#endif
}
- static inline int64_t hton(int64_t n) throw() { return (int64_t)hton((uint64_t)n); }
-
- static inline uint8_t ntoh(uint8_t n) throw() { return n; }
- static inline int8_t ntoh(int8_t n) throw() { return n; }
- static inline uint16_t ntoh(uint16_t n) throw() { return ntohs(n); }
- static inline int16_t ntoh(int16_t n) throw() { return (int16_t)ntohs((uint16_t)n); }
- static inline uint32_t ntoh(uint32_t n) throw() { return ntohl(n); }
- static inline int32_t ntoh(int32_t n) throw() { return (int32_t)ntohl((uint32_t)n); }
+ static inline int64_t hton(int64_t n) { return (int64_t)hton((uint64_t)n); }
+
+ static inline uint8_t ntoh(uint8_t n) { return n; }
+ static inline int8_t ntoh(int8_t n) { return n; }
+ static inline uint16_t ntoh(uint16_t n) { return ntohs(n); }
+ static inline int16_t ntoh(int16_t n) { return (int16_t)ntohs((uint16_t)n); }
+ static inline uint32_t ntoh(uint32_t n) { return ntohl(n); }
+ static inline int32_t ntoh(int32_t n) { return (int32_t)ntohl((uint32_t)n); }
static inline uint64_t ntoh(uint64_t n)
- throw()
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
#if defined(__GNUC__) && !defined(__OpenBSD__)
@@ -341,39 +458,7 @@ public:
return n;
#endif
}
- static inline int64_t ntoh(int64_t n) throw() { return (int64_t)ntoh((uint64_t)n); }
-
- /**
- * Compare Peer version tuples
- *
- * @return -1, 0, or 1 based on whether first tuple is less than, equal to, or greater than second
- */
- static inline int compareVersion(unsigned int maj1,unsigned int min1,unsigned int rev1,unsigned int b1,unsigned int maj2,unsigned int min2,unsigned int rev2,unsigned int b2)
- {
- if (maj1 > maj2)
- return 1;
- else if (maj1 < maj2)
- return -1;
- else {
- if (min1 > min2)
- return 1;
- else if (min1 < min2)
- return -1;
- else {
- if (rev1 > rev2)
- return 1;
- else if (rev1 < rev2)
- return -1;
- else {
- if (b1 > b2)
- return 1;
- else if (b1 < b2)
- return -1;
- else return 0;
- }
- }
- }
- }
+ static inline int64_t ntoh(int64_t n) { return (int64_t)ntoh((uint64_t)n); }
/**
* Hexadecimal characters 0-f