From 3de5cbd1057cc163f50accdd7c872919161d6c45 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 24 Sep 2024 10:31:31 -0400 Subject: [PATCH] Change indent --- node/Packet.cpp | 1502 ++++++++++++++++++------------------- node/Packet.hpp | 1886 +++++++++++++++++++++++------------------------ 2 files changed, 1694 insertions(+), 1694 deletions(-) diff --git a/node/Packet.cpp b/node/Packet.cpp index 4b8b6037f..9c09736ed 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -29,8 +29,8 @@ #ifdef _MSC_VER #define FORCE_INLINE static __forceinline #include -#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ +#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ #else #define FORCE_INLINE static inline #endif @@ -52,8 +52,8 @@ namespace ZeroTier { class _FastCryptoChecker { public: - _FastCryptoChecker() : canHas(zt_arm_has_neon()) {} - bool canHas; + _FastCryptoChecker() : canHas(zt_arm_has_neon()) {} + bool canHas; }; static const _FastCryptoChecker _ZT_FAST_CRYPTO_CHECK; #define ZT_HAS_FAST_CRYPTO() (_ZT_FAST_CRYPTO_CHECK.canHas) @@ -95,9 +95,9 @@ namespace { modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. @@ -115,8 +115,8 @@ namespace { OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 homepage : http://www.lz4.org - - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ /** @@ -128,9 +128,9 @@ namespace { The LZ4 compression library provides in-memory compression and decompression functions. Compression can be done in: - - a single step (described as Simple Functions) - - a single step, reusing a context (described in Advanced Functions) - - unbounded multiple steps (described as Streaming compression) + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) lz4.h provides block compression functions. It gives full buffer control to user. Decompressing an lz4-compressed block also requires metadata (such as compressed size). @@ -142,16 +142,16 @@ namespace { A library is provided to take care of it, see lz4frame.h. */ -#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ -#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ -#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */ +#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ +#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ +#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */ #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) #define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE #define LZ4_QUOTE(str) #str #define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) #define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) #define LZ4_MEMORY_USAGE 14 -#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ +#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ #define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ @@ -160,36 +160,36 @@ static inline void LZ4_resetStream (LZ4_stream_t* streamPtr); #define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) #define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) -#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ +#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ typedef struct { - uint32_t hashTable[LZ4_HASH_SIZE_U32]; - uint32_t currentOffset; - uint32_t initCheck; - const uint8_t* dictionary; - uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ - uint32_t dictSize; + uint32_t hashTable[LZ4_HASH_SIZE_U32]; + uint32_t currentOffset; + uint32_t initCheck; + const uint8_t* dictionary; + uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ + uint32_t dictSize; } LZ4_stream_t_internal; typedef struct { - const uint8_t* externalDict; - size_t extDictSize; - const uint8_t* prefixEnd; - size_t prefixSize; + const uint8_t* externalDict; + size_t extDictSize; + const uint8_t* prefixEnd; + size_t prefixSize; } LZ4_streamDecode_t_internal; #define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) -#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) +#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) union LZ4_stream_u { - unsigned long long table[LZ4_STREAMSIZE_U64]; - LZ4_stream_t_internal internal_donotuse; + unsigned long long table[LZ4_STREAMSIZE_U64]; + LZ4_stream_t_internal internal_donotuse; } ; /* previously typedef'd to LZ4_stream_t */ #define LZ4_STREAMDECODESIZE_U64 4 -#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) +#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) union LZ4_streamDecode_u { - unsigned long long table[LZ4_STREAMDECODESIZE_U64]; - LZ4_streamDecode_t_internal internal_donotuse; + unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + LZ4_streamDecode_t_internal internal_donotuse; } ; /* previously typedef'd to LZ4_streamDecode_t */ #ifndef HEAPMODE @@ -211,8 +211,8 @@ union LZ4_streamDecode_u { #endif #define ALLOCATOR(n,s) calloc(n,s) -#define FREEMEM free -#define MEM_INIT memset +#define FREEMEM free +#define MEM_INIT memset typedef uint8_t BYTE; typedef uint16_t U16; @@ -224,8 +224,8 @@ typedef uintptr_t reg_t; static inline unsigned LZ4_isLittleEndian(void) { - const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ - return one.c[0]; + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; } #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) @@ -244,62 +244,62 @@ static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = val #else /* safe and portable access through memcpy() */ static inline U16 LZ4_read16(const void* memPtr) { - U16 val; memcpy(&val, memPtr, sizeof(val)); return val; + U16 val; memcpy(&val, memPtr, sizeof(val)); return val; } static inline U32 LZ4_read32(const void* memPtr) { - U32 val; memcpy(&val, memPtr, sizeof(val)); return val; + U32 val; memcpy(&val, memPtr, sizeof(val)); return val; } static inline reg_t LZ4_read_ARCH(const void* memPtr) { - reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; + reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; } static inline void LZ4_write16(void* memPtr, U16 value) { - memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } static inline void LZ4_write32(void* memPtr, U32 value) { - memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } #endif /* LZ4_FORCE_MEMORY_ACCESS */ static inline U16 LZ4_readLE16(const void* memPtr) { - if (LZ4_isLittleEndian()) { - return LZ4_read16(memPtr); - } else { - const BYTE* p = (const BYTE*)memPtr; - return (U16)((U16)p[0] + (p[1]<<8)); - } + if (LZ4_isLittleEndian()) { + return LZ4_read16(memPtr); + } else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)((U16)p[0] + (p[1]<<8)); + } } static inline void LZ4_writeLE16(void* memPtr, U16 value) { - if (LZ4_isLittleEndian()) { - LZ4_write16(memPtr, value); - } else { - BYTE* p = (BYTE*)memPtr; - p[0] = (BYTE) value; - p[1] = (BYTE)(value>>8); - } + if (LZ4_isLittleEndian()) { + LZ4_write16(memPtr, value); + } else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE) value; + p[1] = (BYTE)(value>>8); + } } static inline void LZ4_copy8(void* dst, const void* src) { - memcpy(dst,src,8); + memcpy(dst,src,8); } static inline void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) { - BYTE* d = (BYTE*)dstPtr; - const BYTE* s = (const BYTE*)srcPtr; - BYTE* const e = (BYTE*)dstEnd; - do { - LZ4_copy8(d,s); - d+=8; - s+=8; - } while (d>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll((U64)val) >> 3); -# else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; -# endif - } else /* 32 bits */ { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r; - _BitScanForward( &r, (U32)val ); - return (int)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz((U32)val) >> 3); -# else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; -# endif - } - } else /* Big Endian CPU */ { - if (sizeof(val)==8) { -# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll((U64)val) >> 3); -# else - unsigned r; - if (!(val>>32)) { - r=4; - } else { - r=0; - val>>=32; - } - if (!(val>>16)) { - r+=2; - val>>=8; - } else { - val>>=24; - } - r += (!val); - return r; -# endif - } else /* 32 bits */ { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz((U32)val) >> 3); -# else - unsigned r; - if (!(val>>16)) { - r=2; - val>>=8; - } else { - r=0; - val>>=24; - } - r += (!val); - return r; -# endif - } - } + if (LZ4_isLittleEndian()) { + if (sizeof(val)==8) { +# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanForward64( &r, (U64)val ); + return (int)(r>>3); +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctzll((U64)val) >> 3); +# else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif + } else /* 32 bits */ { +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r; + _BitScanForward( &r, (U32)val ); + return (int)(r>>3); +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctz((U32)val) >> 3); +# else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif + } + } else /* Big Endian CPU */ { + if (sizeof(val)==8) { +# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (unsigned)(r>>3); +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clzll((U64)val) >> 3); +# else + unsigned r; + if (!(val>>32)) { + r=4; + } else { + r=0; + val>>=32; + } + if (!(val>>16)) { + r+=2; + val>>=8; + } else { + val>>=24; + } + r += (!val); + return r; +# endif + } else /* 32 bits */ { +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse( &r, (unsigned long)val ); + return (unsigned)(r>>3); +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clz((U32)val) >> 3); +# else + unsigned r; + if (!(val>>16)) { + r=2; + val>>=8; + } else { + r=0; + val>>=24; + } + r += (!val); + return r; +# endif + } + } } #define STEPSIZE sizeof(reg_t) static inline unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) { - const BYTE* const pStart = pIn; + const BYTE* const pStart = pIn; - while (likely(pIn> ((MINMATCH*8)-(LZ4_HASHLOG+1))); - } else { - return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); - } + if (tableType == byU16) { + return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + } else { + return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); + } } static inline U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { - static const U64 prime5bytes = 889523592379ULL; - static const U64 prime8bytes = 11400714785074694791ULL; - const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; - if (LZ4_isLittleEndian()) { - return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); - } else { - return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); - } + static const U64 prime5bytes = 889523592379ULL; + static const U64 prime8bytes = 11400714785074694791ULL; + const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; + if (LZ4_isLittleEndian()) { + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); + } else { + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); + } } FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) { - if ((sizeof(reg_t)==8) && (tableType != byU16)) { - return LZ4_hash5(LZ4_read_ARCH(p), tableType); - } - return LZ4_hash4(LZ4_read32(p), tableType); + if ((sizeof(reg_t)==8) && (tableType != byU16)) { + return LZ4_hash5(LZ4_read_ARCH(p), tableType); + } + return LZ4_hash4(LZ4_read32(p), tableType); } static inline void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { - switch (tableType) { - case byPtr: { - const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; - return; - } - case byU32: { - U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); - return; - } - case byU16: { - U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); - return; - } - } + switch (tableType) { + case byPtr: { + const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; + return; + } + case byU32: { + U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); + return; + } + case byU16: { + U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); + return; + } + } } FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 const h = LZ4_hashPosition(p, tableType); - LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); + U32 const h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); } static inline const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - if (tableType == byPtr) { - const BYTE** hashTable = (const BYTE**) tableBase; - return hashTable[h]; - } - if (tableType == byU32) { - const U32* const hashTable = (U32*) tableBase; - return hashTable[h] + srcBase; - } - { /* default, to ensure a return */ - const U16* const hashTable = (U16*) tableBase; - return hashTable[h] + srcBase; - } + if (tableType == byPtr) { + const BYTE** hashTable = (const BYTE**) tableBase; + return hashTable[h]; + } + if (tableType == byU32) { + const U32* const hashTable = (U32*) tableBase; + return hashTable[h] + srcBase; + } + { /* default, to ensure a return */ + const U16* const hashTable = (U16*) tableBase; + return hashTable[h] + srcBase; + } } FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 const h = LZ4_hashPosition(p, tableType); - return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); + U32 const h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); } FORCE_INLINE int LZ4_compress_generic( - LZ4_stream_t_internal* const cctx, - const char* const source, - char* const dest, - const int inputSize, - const int maxOutputSize, - const limitedOutput_directive outputLimited, - const tableType_t tableType, - const dict_directive dict, - const dictIssue_directive dictIssue, - const U32 acceleration) + LZ4_stream_t_internal* const cctx, + const char* const source, + char* const dest, + const int inputSize, + const int maxOutputSize, + const limitedOutput_directive outputLimited, + const tableType_t tableType, + const dict_directive dict, + const dictIssue_directive dictIssue, + const U32 acceleration) { - const BYTE* ip = (const BYTE*) source; - const BYTE* base; - const BYTE* lowLimit; - const BYTE* const lowRefLimit = ip - cctx->dictSize; - const BYTE* const dictionary = cctx->dictionary; - const BYTE* const dictEnd = dictionary + cctx->dictSize; - const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; - const BYTE* anchor = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = iend - LASTLITERALS; + const BYTE* ip = (const BYTE*) source; + const BYTE* base; + const BYTE* lowLimit; + const BYTE* const lowRefLimit = ip - cctx->dictSize; + const BYTE* const dictionary = cctx->dictionary; + const BYTE* const dictEnd = dictionary + cctx->dictSize; + const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; + const BYTE* anchor = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; - BYTE* op = (BYTE*) dest; - BYTE* const olimit = op + maxOutputSize; + BYTE* op = (BYTE*) dest; + BYTE* const olimit = op + maxOutputSize; - U32 forwardH; + U32 forwardH; - /* Init conditions */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) { - return 0; /* Unsupported inputSize, too large (or negative) */ - } - switch(dict) { - case noDict: - default: - base = (const BYTE*)source; - lowLimit = (const BYTE*)source; - break; - case withPrefix64k: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source - cctx->dictSize; - break; - case usingExtDict: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source; - break; - } - if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) { - return 0; /* Size too large (not within 64K limit) */ - } - if (inputSize (U32)LZ4_MAX_INPUT_SIZE) { + return 0; /* Unsupported inputSize, too large (or negative) */ + } + switch(dict) { + case noDict: + default: + base = (const BYTE*)source; + lowLimit = (const BYTE*)source; + break; + case withPrefix64k: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source - cctx->dictSize; + break; + case usingExtDict: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source; + break; + } + if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) { + return 0; /* Size too large (not within 64K limit) */ + } + if (inputSizehashTable, tableType, base); - ip++; - forwardH = LZ4_hashPosition(ip, tableType); + /* First Byte */ + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + ip++; + forwardH = LZ4_hashPosition(ip, tableType); - /* Main Loop */ - for ( ; ; ) { - ptrdiff_t refDelta = 0; - const BYTE* match; - BYTE* token; + /* Main Loop */ + for ( ; ; ) { + ptrdiff_t refDelta = 0; + const BYTE* match; + BYTE* token; - /* Find a match */ - { - const BYTE* forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = acceleration << LZ4_skipTrigger; - do { - U32 const h = forwardH; - ip = forwardIp; - forwardIp += step; - step = (searchMatchNb++ >> LZ4_skipTrigger); + /* Find a match */ + { + const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); - if (unlikely(forwardIp > mflimit)) { - goto _last_literals; - } + if (unlikely(forwardIp > mflimit)) { + goto _last_literals; + } - match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); - if (dict==usingExtDict) { - if (match < (const BYTE*)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE*)source; - } - } - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); + if (dict==usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } + } + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); - } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) - || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) - || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); - } + } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) + || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); + } - /* Catch up */ - while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { - ip--; - match--; - } + /* Catch up */ + while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { + ip--; + match--; + } - /* Encode Literals */ - { - unsigned const litLength = (unsigned)(ip - anchor); - token = op++; - if ((outputLimited) && /* Check output buffer overflow */ - (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) { - return 0; - } - if (litLength >= RUN_MASK) { - int len = (int)litLength-RUN_MASK; - *token = (RUN_MASK<= 255 ; len-=255) { - *op++ = 255; - } - *op++ = (BYTE)len; - } else { - *token = (BYTE)(litLength< olimit))) { + return 0; + } + if (litLength >= RUN_MASK) { + int len = (int)litLength-RUN_MASK; + *token = (RUN_MASK<= 255 ; len-=255) { + *op++ = 255; + } + *op++ = (BYTE)len; + } else { + *token = (BYTE)(litLength< matchlimit) { - limit = matchlimit; - } - matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); - ip += MINMATCH + matchCode; - if (ip==limit) { - unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); - matchCode += more; - ip += more; - } - } else { - matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); - ip += MINMATCH + matchCode; - } + if ((dict==usingExtDict) && (lowLimit==dictionary)) { + const BYTE* limit; + match += refDelta; + limit = ip + (dictEnd-match); + if (limit > matchlimit) { + limit = matchlimit; + } + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); + ip += MINMATCH + matchCode; + if (ip==limit) { + unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); + matchCode += more; + ip += more; + } + } else { + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + ip += MINMATCH + matchCode; + } - if ( outputLimited && /* Check output buffer overflow */ - (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) { - return 0; - } - if (matchCode >= ML_MASK) { - *token += ML_MASK; - matchCode -= ML_MASK; - LZ4_write32(op, 0xFFFFFFFF); - while (matchCode >= 4*255) { - op+=4; - LZ4_write32(op, 0xFFFFFFFF); - matchCode -= 4*255; - } - op += matchCode / 255; - *op++ = (BYTE)(matchCode % 255); - } else { - *token += (BYTE)(matchCode); - } - } + if ( outputLimited && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) { + return 0; + } + if (matchCode >= ML_MASK) { + *token += ML_MASK; + matchCode -= ML_MASK; + LZ4_write32(op, 0xFFFFFFFF); + while (matchCode >= 4*255) { + op+=4; + LZ4_write32(op, 0xFFFFFFFF); + matchCode -= 4*255; + } + op += matchCode / 255; + *op++ = (BYTE)(matchCode % 255); + } else { + *token += (BYTE)(matchCode); + } + } - anchor = ip; + anchor = ip; - /* Test end of chunk */ - if (ip > mflimit) { - break; - } + /* Test end of chunk */ + if (ip > mflimit) { + break; + } - /* Fill table */ - LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); + /* Fill table */ + LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); - /* Test next position */ - match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); - if (dict==usingExtDict) { - if (match < (const BYTE*)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE*)source; - } - } - LZ4_putPosition(ip, cctx->hashTable, tableType, base); - if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) - && (match+MAX_DISTANCE>=ip) - && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) { - token=op++; - *token=0; - goto _next_match; - } + /* Test next position */ + match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); + if (dict==usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } + } + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) + && (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) { + token=op++; + *token=0; + goto _next_match; + } - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } _last_literals: - /* Encode Last Literals */ - { - size_t const lastRun = (size_t)(iend - anchor); - if ( (outputLimited) && /* Check output buffer overflow */ - ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) { - return 0; - } - if (lastRun >= RUN_MASK) { - size_t accumulator = lastRun - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for(; accumulator >= 255 ; accumulator-=255) { - *op++ = 255; - } - *op++ = (BYTE) accumulator; - } else { - *op++ = (BYTE)(lastRun< (U32)maxOutputSize) ) { + return 0; + } + if (lastRun >= RUN_MASK) { + size_t accumulator = lastRun - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) { + *op++ = 255; + } + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRun<internal_donotuse; - LZ4_resetStream((LZ4_stream_t*)state); - //if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse; + LZ4_resetStream((LZ4_stream_t*)state); + //if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - if (maxOutputSize >= LZ4_compressBound(inputSize)) { - if (inputSize < LZ4_64Klimit) { - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); - } else { - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } - } else { - if (inputSize < LZ4_64Klimit) { - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); - } else { - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } - } + if (maxOutputSize >= LZ4_compressBound(inputSize)) { + if (inputSize < LZ4_64Klimit) { + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); + } else { + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } + } else { + if (inputSize < LZ4_64Klimit) { + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + } else { + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } + } } static inline int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { #if (HEAPMODE) - void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else - LZ4_stream_t ctx; - void* const ctxPtr = &ctx; + LZ4_stream_t ctx; + void* const ctxPtr = &ctx; #endif - int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); + int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); #if (HEAPMODE) - FREEMEM(ctxPtr); + FREEMEM(ctxPtr); #endif - return result; + return result; } static inline void LZ4_resetStream (LZ4_stream_t* LZ4_stream) { - MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); } FORCE_INLINE int LZ4_decompress_generic( - const char* const source, - char* const dest, - int inputSize, - int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ + const char* const source, + char* const dest, + int inputSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ - int endOnInput, /* endOnOutputSize, endOnInputSize */ - int partialDecoding, /* full, partial */ - int targetOutputSize, /* only used if partialDecoding==partial */ - int dict, /* noDict, withPrefix64k, usingExtDict */ - const BYTE* const lowPrefix, /* == dest when no prefix */ - const BYTE* const dictStart, /* only if dict==usingExtDict */ - const size_t dictSize /* note : = 0 if noDict */ - ) + int endOnInput, /* endOnOutputSize, endOnInputSize */ + int partialDecoding, /* full, partial */ + int targetOutputSize, /* only used if partialDecoding==partial */ + int dict, /* noDict, withPrefix64k, usingExtDict */ + const BYTE* const lowPrefix, /* == dest when no prefix */ + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note : = 0 if noDict */ + ) { - /* Local Variables */ - const BYTE* ip = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; + /* Local Variables */ + const BYTE* ip = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; - BYTE* op = (BYTE*) dest; - BYTE* const oend = op + outputSize; - BYTE* cpy; - BYTE* oexit = op + targetOutputSize; - const BYTE* const lowLimit = lowPrefix - dictSize; + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + const BYTE* const lowLimit = lowPrefix - dictSize; - const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; - const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; - const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; + const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; + const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; - const int safeDecode = (endOnInput==endOnInputSize); - const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + const int safeDecode = (endOnInput==endOnInputSize); + const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); - /* Special cases */ - if ((partialDecoding) && (oexit > oend-MFLIMIT)) { - oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ - } - if ((endOnInput) && (unlikely(outputSize==0))) { - return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ - } - if ((!endOnInput) && (unlikely(outputSize==0))) { - return (*ip==0?1:-1); - } + /* Special cases */ + if ((partialDecoding) && (oexit > oend-MFLIMIT)) { + oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ + } + if ((endOnInput) && (unlikely(outputSize==0))) { + return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ + } + if ((!endOnInput) && (unlikely(outputSize==0))) { + return (*ip==0?1:-1); + } - /* Main Loop : decode sequences */ - while (1) { - size_t length; - const BYTE* match; - size_t offset; + /* Main Loop : decode sequences */ + while (1) { + size_t length; + const BYTE* match; + size_t offset; - /* get literal length */ - unsigned const token = *ip++; - if ((length=(token>>ML_BITS)) == RUN_MASK) { - unsigned s; - do { - s = *ip++; - length += s; - } while ( likely(endOnInput ? ip>ML_BITS)) == RUN_MASK) { + unsigned s; + do { + s = *ip++; + length += s; + } while ( likely(endOnInput ? ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) - || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) { - if (partialDecoding) { - if (cpy > oend) { - goto _output_error; /* Error : write attempt beyond end of output buffer */ - } - if ((endOnInput) && (ip+length > iend)) { - goto _output_error; /* Error : read attempt beyond end of input buffer */ - } - } else { - if ((!endOnInput) && (cpy != oend)) { - goto _output_error; /* Error : block decoding must stop exactly there */ - } - if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) { - goto _output_error; /* Error : input must be consumed */ - } - } - memcpy(op, ip, length); - ip += length; - op += length; - break; /* Necessarily EOF, due to parsing restrictions */ - } - LZ4_wildCopy(op, ip, cpy); - ip += length; - op = cpy; + /* copy literals */ + cpy = op+length; + if ( ((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) + || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) { + if (partialDecoding) { + if (cpy > oend) { + goto _output_error; /* Error : write attempt beyond end of output buffer */ + } + if ((endOnInput) && (ip+length > iend)) { + goto _output_error; /* Error : read attempt beyond end of input buffer */ + } + } else { + if ((!endOnInput) && (cpy != oend)) { + goto _output_error; /* Error : block decoding must stop exactly there */ + } + if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) { + goto _output_error; /* Error : input must be consumed */ + } + } + memcpy(op, ip, length); + ip += length; + op += length; + break; /* Necessarily EOF, due to parsing restrictions */ + } + LZ4_wildCopy(op, ip, cpy); + ip += length; + op = cpy; - /* get offset */ - offset = LZ4_readLE16(ip); - ip += 2; - match = op - offset; - if ((checkOffset) && (unlikely(match < lowLimit))) { - goto _output_error; /* Error : offset outside buffers */ - } - LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ + /* get offset */ + offset = LZ4_readLE16(ip); + ip += 2; + match = op - offset; + if ((checkOffset) && (unlikely(match < lowLimit))) { + goto _output_error; /* Error : offset outside buffers */ + } + LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ - /* get matchlength */ - length = token & ML_MASK; - if (length == ML_MASK) { - unsigned s; - do { - s = *ip++; - if ((endOnInput) && (ip > iend-LASTLITERALS)) { - goto _output_error; - } - length += s; - } while (s==255); - if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) { - goto _output_error; /* overflow detection */ - } - } - length += MINMATCH; + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { + unsigned s; + do { + s = *ip++; + if ((endOnInput) && (ip > iend-LASTLITERALS)) { + goto _output_error; + } + length += s; + } while (s==255); + if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) { + goto _output_error; /* overflow detection */ + } + } + length += MINMATCH; - /* check external dictionary */ - if ((dict==usingExtDict) && (match < lowPrefix)) { - if (unlikely(op+length > oend-LASTLITERALS)) { - goto _output_error; /* doesn't respect parsing restriction */ - } + /* check external dictionary */ + if ((dict==usingExtDict) && (match < lowPrefix)) { + if (unlikely(op+length > oend-LASTLITERALS)) { + goto _output_error; /* doesn't respect parsing restriction */ + } - if (length <= (size_t)(lowPrefix-match)) { - /* match can be copied as a single segment from external dictionary */ - memmove(op, dictEnd - (lowPrefix-match), length); - op += length; - } else { - /* match encompass external dictionary and current block */ - size_t const copySize = (size_t)(lowPrefix-match); - size_t const restSize = length - copySize; - memcpy(op, dictEnd - copySize, copySize); - op += copySize; - if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ - BYTE* const endOfMatch = op + restSize; - const BYTE* copyFrom = lowPrefix; - while (op < endOfMatch) { - *op++ = *copyFrom++; - } - } else { - memcpy(op, lowPrefix, restSize); - op += restSize; - } - } - continue; - } + if (length <= (size_t)(lowPrefix-match)) { + /* match can be copied as a single segment from external dictionary */ + memmove(op, dictEnd - (lowPrefix-match), length); + op += length; + } else { + /* match encompass external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix-match); + size_t const restSize = length - copySize; + memcpy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) { + *op++ = *copyFrom++; + } + } else { + memcpy(op, lowPrefix, restSize); + op += restSize; + } + } + continue; + } - /* copy match within block */ - cpy = op + length; - if (unlikely(offset<8)) { - const int dec64 = dec64table[offset]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[offset]; - memcpy(op+4, match, 4); - match -= dec64; - } else { - LZ4_copy8(op, match); - match+=8; - } - op += 8; + /* copy match within block */ + cpy = op + length; + if (unlikely(offset<8)) { + const int dec64 = dec64table[offset]; + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += dec32table[offset]; + memcpy(op+4, match, 4); + match -= dec64; + } else { + LZ4_copy8(op, match); + match+=8; + } + op += 8; - if (unlikely(cpy>oend-12)) { - BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); - if (cpy > oend-LASTLITERALS) { - goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ - } - if (op < oCopyLimit) { - LZ4_wildCopy(op, match, oCopyLimit); - match += oCopyLimit - op; - op = oCopyLimit; - } - while (op16) { - LZ4_wildCopy(op+8, match+8, cpy); - } - } - op=cpy; /* correction */ - } + if (unlikely(cpy>oend-12)) { + BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); + if (cpy > oend-LASTLITERALS) { + goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ + } + if (op < oCopyLimit) { + LZ4_wildCopy(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; + } + while (op16) { + LZ4_wildCopy(op+8, match+8, cpy); + } + } + op=cpy; /* correction */ + } - /* end of decoding */ - if (endOnInput) { - return (int) (((char*)op)-dest); /* Nb of output bytes decoded */ - } else { - return (int) (((const char*)ip)-source); /* Nb of input bytes read */ - } - /* Overflow error detected */ + /* end of decoding */ + if (endOnInput) { + return (int) (((char*)op)-dest); /* Nb of output bytes decoded */ + } else { + return (int) (((const char*)ip)-source); /* Nb of input bytes read */ + } + /* Overflow error detected */ _output_error: - return (int) (-(((const char*)ip)-source))-1; + return (int) (-(((const char*)ip)-source))-1; } static inline int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); } } // anonymous namespace @@ -1007,193 +1007,193 @@ const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 void Packet::armor(const void *key,bool encryptPayload,bool extendedArmor,const AES aesKeys[2],const Identity &identity) { - uint8_t *const data = reinterpret_cast(unsafeData()); + uint8_t *const data = reinterpret_cast(unsafeData()); - if (extendedArmor) { - } + if (extendedArmor) { + } - if ((aesKeys) && (encryptPayload)) { - setCipher(ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV); + if ((aesKeys) && (encryptPayload)) { + setCipher(ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV); - uint8_t *const payload = data + ZT_PACKET_IDX_VERB; - const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; + uint8_t *const payload = data + ZT_PACKET_IDX_VERB; + const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - AES::GMACSIVEncryptor enc(aesKeys[0],aesKeys[1]); - enc.init(Utils::loadMachineEndian(data + ZT_PACKET_IDX_IV),payload); - enc.aad(data + ZT_PACKET_IDX_DEST,11); - enc.update1(payload,payloadLen); - enc.finish1(); - enc.update2(payload,payloadLen); - const uint64_t *const tag = enc.finish2(); + AES::GMACSIVEncryptor enc(aesKeys[0],aesKeys[1]); + enc.init(Utils::loadMachineEndian(data + ZT_PACKET_IDX_IV),payload); + enc.aad(data + ZT_PACKET_IDX_DEST,11); + enc.update1(payload,payloadLen); + enc.finish1(); + enc.update2(payload,payloadLen); + const uint64_t *const tag = enc.finish2(); #ifdef ZT_NO_UNALIGNED_ACCESS - Utils::copy<8>(data,tag); - Utils::copy<8>(data + ZT_PACKET_IDX_MAC,tag + 1); + Utils::copy<8>(data,tag); + Utils::copy<8>(data + ZT_PACKET_IDX_MAC,tag + 1); #else - *reinterpret_cast(data + ZT_PACKET_IDX_IV) = tag[0]; - *reinterpret_cast(data + ZT_PACKET_IDX_MAC) = tag[1]; + *reinterpret_cast(data + ZT_PACKET_IDX_IV) = tag[0]; + *reinterpret_cast(data + ZT_PACKET_IDX_MAC) = tag[1]; #endif - } else { - setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); + } else { + setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); - uint8_t mangledKey[32]; - _salsa20MangleKey((const unsigned char *)key,mangledKey); + uint8_t mangledKey[32]; + _salsa20MangleKey((const unsigned char *)key,mangledKey); - if (ZT_HAS_FAST_CRYPTO()) { - const unsigned int payloadLen = (encryptPayload) ? (size() - ZT_PACKET_IDX_VERB) : 0; - uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8]; - ZT_FAST_SINGLE_PASS_SALSA2012(keyStream,payloadLen + 64,(data + ZT_PACKET_IDX_IV),mangledKey); - Salsa20::memxor(data + ZT_PACKET_IDX_VERB,reinterpret_cast(keyStream + 8),payloadLen); - uint64_t mac[2]; - Poly1305::compute(mac,data + ZT_PACKET_IDX_VERB,size() - ZT_PACKET_IDX_VERB,keyStream); + if (ZT_HAS_FAST_CRYPTO()) { + const unsigned int payloadLen = (encryptPayload) ? (size() - ZT_PACKET_IDX_VERB) : 0; + uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8]; + ZT_FAST_SINGLE_PASS_SALSA2012(keyStream,payloadLen + 64,(data + ZT_PACKET_IDX_IV),mangledKey); + Salsa20::memxor(data + ZT_PACKET_IDX_VERB,reinterpret_cast(keyStream + 8),payloadLen); + uint64_t mac[2]; + Poly1305::compute(mac,data + ZT_PACKET_IDX_VERB,size() - ZT_PACKET_IDX_VERB,keyStream); #ifdef ZT_NO_TYPE_PUNNING - memcpy(data + ZT_PACKET_IDX_MAC,mac,8); + memcpy(data + ZT_PACKET_IDX_MAC,mac,8); #else - (*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) = mac[0]; + (*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) = mac[0]; #endif - } else { - Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV); + } else { + Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV); - uint64_t macKey[4]; - s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); + uint64_t macKey[4]; + s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); - uint8_t *const payload = data + ZT_PACKET_IDX_VERB; - const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - if (encryptPayload) { - s20.crypt12(payload,payload,payloadLen); - } - uint64_t mac[2]; + uint8_t *const payload = data + ZT_PACKET_IDX_VERB; + const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; + if (encryptPayload) { + s20.crypt12(payload,payload,payloadLen); + } + uint64_t mac[2]; - Poly1305::compute(mac,payload,payloadLen,macKey); - memcpy(data + ZT_PACKET_IDX_MAC,mac,8); - } - } + Poly1305::compute(mac,payload,payloadLen,macKey); + memcpy(data + ZT_PACKET_IDX_MAC,mac,8); + } + } } bool Packet::dearmor(const void *key,const AES aesKeys[2],const Identity &identity) { - uint8_t *const data = reinterpret_cast(unsafeData()); - const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - unsigned char *const payload = data + ZT_PACKET_IDX_VERB; - const unsigned int cs = cipher(); + uint8_t *const data = reinterpret_cast(unsafeData()); + const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; + unsigned char *const payload = data + ZT_PACKET_IDX_VERB; + const unsigned int cs = cipher(); - if (cs == ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV) { - if (aesKeys) { - uint64_t tag[2]; + if (cs == ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV) { + if (aesKeys) { + uint64_t tag[2]; #ifdef ZT_NO_UNALIGNED_ACCESS - Utils::copy<8>(tag, data); - Utils::copy<8>(tag + 1, data + ZT_PACKET_IDX_MAC); + Utils::copy<8>(tag, data); + Utils::copy<8>(tag + 1, data + ZT_PACKET_IDX_MAC); #else - tag[0] = *reinterpret_cast(data + ZT_PACKET_IDX_IV); - tag[1] = *reinterpret_cast(data + ZT_PACKET_IDX_MAC); + tag[0] = *reinterpret_cast(data + ZT_PACKET_IDX_IV); + tag[1] = *reinterpret_cast(data + ZT_PACKET_IDX_MAC); #endif - AES::GMACSIVDecryptor dec(aesKeys[0],aesKeys[1]); - dec.init(tag, payload); - const uint8_t oldFlags = data[ZT_PACKET_IDX_FLAGS]; - data[ZT_PACKET_IDX_FLAGS] &= 0xf8; - dec.aad(data + ZT_PACKET_IDX_DEST,11); - data[ZT_PACKET_IDX_FLAGS] = oldFlags; - dec.update(payload, payloadLen); - return dec.finish(); - } - } else if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) { - uint8_t mangledKey[32]; - _salsa20MangleKey((const unsigned char *)key,mangledKey); - if (ZT_HAS_FAST_CRYPTO()) { - uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8]; - ZT_FAST_SINGLE_PASS_SALSA2012(keyStream,((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) ? (payloadLen + 64) : 64),(data + ZT_PACKET_IDX_IV),mangledKey); - uint64_t mac[2]; - Poly1305::compute(mac,payload,payloadLen,keyStream); + AES::GMACSIVDecryptor dec(aesKeys[0],aesKeys[1]); + dec.init(tag, payload); + const uint8_t oldFlags = data[ZT_PACKET_IDX_FLAGS]; + data[ZT_PACKET_IDX_FLAGS] &= 0xf8; + dec.aad(data + ZT_PACKET_IDX_DEST,11); + data[ZT_PACKET_IDX_FLAGS] = oldFlags; + dec.update(payload, payloadLen); + return dec.finish(); + } + } else if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) { + uint8_t mangledKey[32]; + _salsa20MangleKey((const unsigned char *)key,mangledKey); + if (ZT_HAS_FAST_CRYPTO()) { + uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8]; + ZT_FAST_SINGLE_PASS_SALSA2012(keyStream,((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) ? (payloadLen + 64) : 64),(data + ZT_PACKET_IDX_IV),mangledKey); + uint64_t mac[2]; + Poly1305::compute(mac,payload,payloadLen,keyStream); #ifdef ZT_NO_TYPE_PUNNING - if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) { - return false; - } + if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) { + return false; + } #else - if ((*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) != mac[0]) { // also secure, constant time - return false; - } + if ((*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) != mac[0]) { // also secure, constant time + return false; + } #endif - if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) { - Salsa20::memxor(data + ZT_PACKET_IDX_VERB,reinterpret_cast(keyStream + 8),payloadLen); - } - } else { - Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV); - uint64_t macKey[4]; - s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); - uint64_t mac[2]; - Poly1305::compute(mac,payload,payloadLen,macKey); + if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) { + Salsa20::memxor(data + ZT_PACKET_IDX_VERB,reinterpret_cast(keyStream + 8),payloadLen); + } + } else { + Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV); + uint64_t macKey[4]; + s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); + uint64_t mac[2]; + Poly1305::compute(mac,payload,payloadLen,macKey); #ifdef ZT_NO_TYPE_PUNNING - if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) { - return false; - } + if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) { + return false; + } #else - if ((*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) != mac[0]) { // also secure, constant time - return false; - } + if ((*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) != mac[0]) { // also secure, constant time + return false; + } #endif - if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) { - s20.crypt12(payload,payload,payloadLen); - } - } - return true; - } + if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) { + s20.crypt12(payload,payload,payloadLen); + } + } + return true; + } - return false; + return false; } void Packet::cryptField(const void *key,unsigned int start,unsigned int len) { - uint8_t *const data = reinterpret_cast(unsafeData()); - uint8_t iv[8]; - for(int i=0;i<8;++i) { - iv[i] = data[i]; - } - iv[7] &= 0xf8; // mask off least significant 3 bits of packet ID / IV since this is unset when this function gets called - Salsa20 s20(key,iv); - s20.crypt12(data + start,data + start,len); + uint8_t *const data = reinterpret_cast(unsafeData()); + uint8_t iv[8]; + for(int i=0;i<8;++i) { + iv[i] = data[i]; + } + iv[7] &= 0xf8; // mask off least significant 3 bits of packet ID / IV since this is unset when this function gets called + Salsa20 s20(key,iv); + s20.crypt12(data + start,data + start,len); } bool Packet::compress() { - char *const data = reinterpret_cast(unsafeData()); - char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2]; + char *const data = reinterpret_cast(unsafeData()); + char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2]; - if ((!compressed())&&(size() > (ZT_PACKET_IDX_PAYLOAD + 64))) { // don't bother compressing tiny packets - int pl = (int)(size() - ZT_PACKET_IDX_PAYLOAD); - int cl = LZ4_compress_fast(data + ZT_PACKET_IDX_PAYLOAD,buf,pl,ZT_PROTO_MAX_PACKET_LENGTH * 2,1); - if ((cl > 0)&&(cl < pl)) { - data[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED; - setSize((unsigned int)cl + ZT_PACKET_IDX_PAYLOAD); - memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,cl); - return true; - } - } - data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); + if ((!compressed())&&(size() > (ZT_PACKET_IDX_PAYLOAD + 64))) { // don't bother compressing tiny packets + int pl = (int)(size() - ZT_PACKET_IDX_PAYLOAD); + int cl = LZ4_compress_fast(data + ZT_PACKET_IDX_PAYLOAD,buf,pl,ZT_PROTO_MAX_PACKET_LENGTH * 2,1); + if ((cl > 0)&&(cl < pl)) { + data[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED; + setSize((unsigned int)cl + ZT_PACKET_IDX_PAYLOAD); + memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,cl); + return true; + } + } + data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); - return false; + return false; } bool Packet::uncompress() { - char *const data = reinterpret_cast(unsafeData()); - char buf[ZT_PROTO_MAX_PACKET_LENGTH]; + char *const data = reinterpret_cast(unsafeData()); + char buf[ZT_PROTO_MAX_PACKET_LENGTH]; - if ((compressed())&&(size() >= ZT_PROTO_MIN_PACKET_LENGTH)) { - if (size() > ZT_PACKET_IDX_PAYLOAD) { - unsigned int compLen = size() - ZT_PACKET_IDX_PAYLOAD; - int ucl = LZ4_decompress_safe((const char *)data + ZT_PACKET_IDX_PAYLOAD,buf,compLen,sizeof(buf)); - if ((ucl > 0)&&(ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) { - setSize((unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD); - memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,ucl); - } else { - return false; - } - } - data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); - } + if ((compressed())&&(size() >= ZT_PROTO_MIN_PACKET_LENGTH)) { + if (size() > ZT_PACKET_IDX_PAYLOAD) { + unsigned int compLen = size() - ZT_PACKET_IDX_PAYLOAD; + int ucl = LZ4_decompress_safe((const char *)data + ZT_PACKET_IDX_PAYLOAD,buf,compLen,sizeof(buf)); + if ((ucl > 0)&&(ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) { + setSize((unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD); + memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,ucl); + } else { + return false; + } + } + data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); + } - return true; + return true; } } // namespace ZeroTier diff --git a/node/Packet.hpp b/node/Packet.hpp index c2391b957..da889cae4 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -348,1038 +348,1038 @@ namespace ZeroTier { class Packet : public Buffer { public: - /** - * A packet fragment - * - * Fragments are sent if a packet is larger than UDP MTU. The first fragment - * is sent with its normal header with the fragmented flag set. Remaining - * fragments are sent this way. - * - * The fragmented bit indicates that there is at least one fragment. Fragments - * themselves contain the total, so the receiver must "learn" this from the - * first fragment it receives. - * - * Fragments are sent with the following format: - * <[8] packet ID of packet whose fragment this belongs to> - * <[5] destination ZT address> - * <[1] 0xff, a reserved address, signals that this isn't a normal packet> - * <[1] total fragments (most significant 4 bits), fragment no (LS 4 bits)> - * <[1] ZT hop count (top 5 bits unused and must be zero)> - * <[...] fragment data> - * - * The protocol supports a maximum of 16 fragments. If a fragment is received - * before its main packet header, it should be cached for a brief period of - * time to see if its parent arrives. Loss of any fragment constitutes packet - * loss; there is no retransmission mechanism. The receiver must wait for full - * receipt to authenticate and decrypt; there is no per-fragment MAC. (But if - * fragments are corrupt, the MAC will fail for the whole assembled packet.) - */ - class Fragment : public Buffer - { - public: - Fragment() : - Buffer() - { - } + /** + * A packet fragment + * + * Fragments are sent if a packet is larger than UDP MTU. The first fragment + * is sent with its normal header with the fragmented flag set. Remaining + * fragments are sent this way. + * + * The fragmented bit indicates that there is at least one fragment. Fragments + * themselves contain the total, so the receiver must "learn" this from the + * first fragment it receives. + * + * Fragments are sent with the following format: + * <[8] packet ID of packet whose fragment this belongs to> + * <[5] destination ZT address> + * <[1] 0xff, a reserved address, signals that this isn't a normal packet> + * <[1] total fragments (most significant 4 bits), fragment no (LS 4 bits)> + * <[1] ZT hop count (top 5 bits unused and must be zero)> + * <[...] fragment data> + * + * The protocol supports a maximum of 16 fragments. If a fragment is received + * before its main packet header, it should be cached for a brief period of + * time to see if its parent arrives. Loss of any fragment constitutes packet + * loss; there is no retransmission mechanism. The receiver must wait for full + * receipt to authenticate and decrypt; there is no per-fragment MAC. (But if + * fragments are corrupt, the MAC will fail for the whole assembled packet.) + */ + class Fragment : public Buffer + { + public: + Fragment() : + Buffer() + { + } - template - Fragment(const Buffer &b) : - Buffer(b) - { - } + template + Fragment(const Buffer &b) : + Buffer(b) + { + } - Fragment(const void *data,unsigned int len) : - Buffer(data,len) - { - } + Fragment(const void *data,unsigned int len) : + Buffer(data,len) + { + } - /** - * Initialize from a packet - * - * @param p Original assembled packet - * @param fragStart Start of fragment (raw index in packet data) - * @param fragLen Length of fragment in bytes - * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) - * @param fragTotal Total number of fragments (including 0) - */ - Fragment(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) - { - init(p,fragStart,fragLen,fragNo,fragTotal); - } + /** + * Initialize from a packet + * + * @param p Original assembled packet + * @param fragStart Start of fragment (raw index in packet data) + * @param fragLen Length of fragment in bytes + * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) + * @param fragTotal Total number of fragments (including 0) + */ + Fragment(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) + { + init(p,fragStart,fragLen,fragNo,fragTotal); + } - /** - * Initialize from a packet - * - * @param p Original assembled packet - * @param fragStart Start of fragment (raw index in packet data) - * @param fragLen Length of fragment in bytes - * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) - * @param fragTotal Total number of fragments (including 0) - */ - inline void init(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) - { - if ((fragStart + fragLen) > p.size()) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH); + /** + * Initialize from a packet + * + * @param p Original assembled packet + * @param fragStart Start of fragment (raw index in packet data) + * @param fragLen Length of fragment in bytes + * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) + * @param fragTotal Total number of fragments (including 0) + */ + inline void init(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) + { + if ((fragStart + fragLen) > p.size()) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH); - // NOTE: this copies both the IV/packet ID and the destination address. - memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID,13),p.field(ZT_PACKET_IDX_IV,13),13); + // NOTE: this copies both the IV/packet ID and the destination address. + memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID,13),p.field(ZT_PACKET_IDX_IV,13),13); - (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR; - (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf)); - (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0; + (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR; + (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf)); + (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0; - memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,fragLen),p.field(fragStart,fragLen),fragLen); - } + memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,fragLen),p.field(fragStart,fragLen),fragLen); + } - /** - * Get this fragment's destination - * - * @return Destination ZT address - */ - inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } + /** + * Get this fragment's destination + * + * @return Destination ZT address + */ + inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - /** - * @return True if fragment is of a valid length - */ - inline bool lengthValid() const { return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); } + /** + * @return True if fragment is of a valid length + */ + inline bool lengthValid() const { return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); } - /** - * @return ID of packet this is a fragment of - */ - inline uint64_t packetId() const { return at(ZT_PACKET_FRAGMENT_IDX_PACKET_ID); } + /** + * @return ID of packet this is a fragment of + */ + inline uint64_t packetId() const { return at(ZT_PACKET_FRAGMENT_IDX_PACKET_ID); } - /** - * @return Total number of fragments in packet - */ - inline unsigned int totalFragments() const { return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf); } + /** + * @return Total number of fragments in packet + */ + inline unsigned int totalFragments() const { return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf); } - /** - * @return Fragment number of this fragment - */ - inline unsigned int fragmentNumber() const { return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf); } + /** + * @return Fragment number of this fragment + */ + inline unsigned int fragmentNumber() const { return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf); } - /** - * @return Fragment ZT hop count - */ - inline unsigned int hops() const { return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]); } + /** + * @return Fragment ZT hop count + */ + inline unsigned int hops() const { return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]); } - /** - * Increment this packet's hop count - */ - inline void incrementHops() - { - (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = (((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]) + 1) & ZT_PROTO_MAX_HOPS; - } + /** + * Increment this packet's hop count + */ + inline void incrementHops() + { + (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = (((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]) + 1) & ZT_PROTO_MAX_HOPS; + } - /** - * @return Length of payload in bytes - */ - inline unsigned int payloadLength() const { return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); } + /** + * @return Length of payload in bytes + */ + inline unsigned int payloadLength() const { return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); } - /** - * @return Raw packet payload - */ - inline const unsigned char *payload() const - { - return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD); - } - }; + /** + * @return Raw packet payload + */ + inline const unsigned char *payload() const + { + return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD); + } + }; - /** - * ZeroTier protocol verbs - */ - enum Verb /* Max value: 32 (5 bits) */ - { - /** - * No operation (ignored, no reply) - */ - VERB_NOP = 0x00, + /** + * ZeroTier protocol verbs + */ + enum Verb /* Max value: 32 (5 bits) */ + { + /** + * No operation (ignored, no reply) + */ + VERB_NOP = 0x00, - /** - * Announcement of a node's existence and vitals: - * <[1] protocol version> - * <[1] software major version> - * <[1] software minor version> - * <[2] software revision> - * <[8] timestamp for determining latency> - * <[...] binary serialized identity (see Identity)> - * <[...] physical destination address of packet> - * <[8] 64-bit world ID of current planet> - * <[8] 64-bit timestamp of current planet> - * [... remainder if packet is encrypted using cryptField() ...] - * <[2] 16-bit number of moons> - * [<[1] 8-bit type ID of moon>] - * [<[8] 64-bit world ID of moon>] - * [<[8] 64-bit timestamp of moon>] - * [... additional moon type/ID/timestamp tuples ...] - * - * HELLO is sent in the clear as it is how peers share their identity - * public keys. A few additional fields are sent in the clear too, but - * these are things that are public info or are easy to determine. As - * of 1.2.0 we have added a few more fields, but since these could have - * the potential to be sensitive we introduced the encryption of the - * remainder of the packet. See cryptField(). Packet MAC is still - * performed of course, so authentication occurs as normal. - * - * Destination address is the actual wire address to which the packet - * was sent. See InetAddress::serialize() for format. - * - * OK payload: - * <[8] HELLO timestamp field echo> - * <[1] protocol version> - * <[1] software major version> - * <[1] software minor version> - * <[2] software revision> - * <[...] physical destination address of packet> - * <[2] 16-bit length of world update(s) or 0 if none> - * [[...] updates to planets and/or moons] - * - * With the exception of the timestamp, the other fields pertain to the - * respondent who is sending OK and are not echoes. - * - * Note that OK is fully encrypted so no selective cryptField() of - * potentially sensitive fields is needed. - * - * ERROR has no payload. - */ - VERB_HELLO = 0x01, + /** + * Announcement of a node's existence and vitals: + * <[1] protocol version> + * <[1] software major version> + * <[1] software minor version> + * <[2] software revision> + * <[8] timestamp for determining latency> + * <[...] binary serialized identity (see Identity)> + * <[...] physical destination address of packet> + * <[8] 64-bit world ID of current planet> + * <[8] 64-bit timestamp of current planet> + * [... remainder if packet is encrypted using cryptField() ...] + * <[2] 16-bit number of moons> + * [<[1] 8-bit type ID of moon>] + * [<[8] 64-bit world ID of moon>] + * [<[8] 64-bit timestamp of moon>] + * [... additional moon type/ID/timestamp tuples ...] + * + * HELLO is sent in the clear as it is how peers share their identity + * public keys. A few additional fields are sent in the clear too, but + * these are things that are public info or are easy to determine. As + * of 1.2.0 we have added a few more fields, but since these could have + * the potential to be sensitive we introduced the encryption of the + * remainder of the packet. See cryptField(). Packet MAC is still + * performed of course, so authentication occurs as normal. + * + * Destination address is the actual wire address to which the packet + * was sent. See InetAddress::serialize() for format. + * + * OK payload: + * <[8] HELLO timestamp field echo> + * <[1] protocol version> + * <[1] software major version> + * <[1] software minor version> + * <[2] software revision> + * <[...] physical destination address of packet> + * <[2] 16-bit length of world update(s) or 0 if none> + * [[...] updates to planets and/or moons] + * + * With the exception of the timestamp, the other fields pertain to the + * respondent who is sending OK and are not echoes. + * + * Note that OK is fully encrypted so no selective cryptField() of + * potentially sensitive fields is needed. + * + * ERROR has no payload. + */ + VERB_HELLO = 0x01, - /** - * Error response: - * <[1] in-re verb> - * <[8] in-re packet ID> - * <[1] error code> - * <[...] error-dependent payload> - */ - VERB_ERROR = 0x02, + /** + * Error response: + * <[1] in-re verb> + * <[8] in-re packet ID> + * <[1] error code> + * <[...] error-dependent payload> + */ + VERB_ERROR = 0x02, - /** - * Success response: - * <[1] in-re verb> - * <[8] in-re packet ID> - * <[...] request-specific payload> - */ - VERB_OK = 0x03, + /** + * Success response: + * <[1] in-re verb> + * <[8] in-re packet ID> + * <[...] request-specific payload> + */ + VERB_OK = 0x03, - /** - * Query an identity by address: - * <[5] address to look up> - * [<[...] additional addresses to look up> - * - * OK response payload: - * <[...] binary serialized identity> - * [<[...] additional binary serialized identities>] - * - * If querying a cluster, duplicate OK responses may occasionally occur. - * These must be tolerated, which is easy since they'll have info you - * already have. - * - * If the address is not found, no response is generated. The semantics - * of WHOIS is similar to ARP and NDP in that persistent retrying can - * be performed. - */ - VERB_WHOIS = 0x04, + /** + * Query an identity by address: + * <[5] address to look up> + * [<[...] additional addresses to look up> + * + * OK response payload: + * <[...] binary serialized identity> + * [<[...] additional binary serialized identities>] + * + * If querying a cluster, duplicate OK responses may occasionally occur. + * These must be tolerated, which is easy since they'll have info you + * already have. + * + * If the address is not found, no response is generated. The semantics + * of WHOIS is similar to ARP and NDP in that persistent retrying can + * be performed. + */ + VERB_WHOIS = 0x04, - /** - * Relay-mediated NAT traversal or firewall punching initiation: - * <[1] flags (unused, currently 0)> - * <[5] ZeroTier address of peer that might be found at this address> - * <[2] 16-bit protocol address port> - * <[1] protocol address length (4 for IPv4, 16 for IPv6)> - * <[...] protocol address (network byte order)> - * - * An upstream node can send this to inform both sides of a relay of - * information they might use to establish a direct connection. - * - * Upon receipt a peer sends HELLO to establish a direct link. - * - * No OK or ERROR is generated. - */ - VERB_RENDEZVOUS = 0x05, + /** + * Relay-mediated NAT traversal or firewall punching initiation: + * <[1] flags (unused, currently 0)> + * <[5] ZeroTier address of peer that might be found at this address> + * <[2] 16-bit protocol address port> + * <[1] protocol address length (4 for IPv4, 16 for IPv6)> + * <[...] protocol address (network byte order)> + * + * An upstream node can send this to inform both sides of a relay of + * information they might use to establish a direct connection. + * + * Upon receipt a peer sends HELLO to establish a direct link. + * + * No OK or ERROR is generated. + */ + VERB_RENDEZVOUS = 0x05, - /** - * ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME): - * <[8] 64-bit network ID> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * MAC addresses are derived from the packet's source and destination - * ZeroTier addresses. This is a shortened EXT_FRAME that elides full - * Ethernet framing and other optional flags and features when they - * are not necessary. - * - * ERROR may be generated if a membership certificate is needed for a - * closed network. Payload will be network ID. - */ - VERB_FRAME = 0x06, + /** + * ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME): + * <[8] 64-bit network ID> + * <[2] 16-bit ethertype> + * <[...] ethernet payload> + * + * MAC addresses are derived from the packet's source and destination + * ZeroTier addresses. This is a shortened EXT_FRAME that elides full + * Ethernet framing and other optional flags and features when they + * are not necessary. + * + * ERROR may be generated if a membership certificate is needed for a + * closed network. Payload will be network ID. + */ + VERB_FRAME = 0x06, - /** - * Full Ethernet frame with MAC addressing and optional fields: - * <[8] 64-bit network ID> - * <[1] flags> - * <[6] destination MAC or all zero for destination node> - * <[6] source MAC or all zero for node of origin> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * Flags: - * 0x01 - Certificate of network membership attached (DEPRECATED) - * 0x02 - Most significant bit of subtype (see below) - * 0x04 - Middle bit of subtype (see below) - * 0x08 - Least significant bit of subtype (see below) - * 0x10 - ACK requested in the form of OK(EXT_FRAME) - * - * Subtypes (0..7): - * 0x0 - Normal frame (bridging can be determined by checking MAC) - * 0x1 - TEEd outbound frame - * 0x2 - REDIRECTed outbound frame - * 0x3 - WATCHed outbound frame (TEE with ACK, ACK bit also set) - * 0x4 - TEEd inbound frame - * 0x5 - REDIRECTed inbound frame - * 0x6 - WATCHed inbound frame - * 0x7 - (reserved for future use) - * - * An extended frame carries full MAC addressing, making it a - * superset of VERB_FRAME. It is used for bridged traffic, - * redirected or observed traffic via rules, and can in theory - * be used for multicast though MULTICAST_FRAME exists for that - * purpose and has additional options and capabilities. - * - * OK payload (if ACK flag is set): - * <[8] 64-bit network ID> - */ - VERB_EXT_FRAME = 0x07, + /** + * Full Ethernet frame with MAC addressing and optional fields: + * <[8] 64-bit network ID> + * <[1] flags> + * <[6] destination MAC or all zero for destination node> + * <[6] source MAC or all zero for node of origin> + * <[2] 16-bit ethertype> + * <[...] ethernet payload> + * + * Flags: + * 0x01 - Certificate of network membership attached (DEPRECATED) + * 0x02 - Most significant bit of subtype (see below) + * 0x04 - Middle bit of subtype (see below) + * 0x08 - Least significant bit of subtype (see below) + * 0x10 - ACK requested in the form of OK(EXT_FRAME) + * + * Subtypes (0..7): + * 0x0 - Normal frame (bridging can be determined by checking MAC) + * 0x1 - TEEd outbound frame + * 0x2 - REDIRECTed outbound frame + * 0x3 - WATCHed outbound frame (TEE with ACK, ACK bit also set) + * 0x4 - TEEd inbound frame + * 0x5 - REDIRECTed inbound frame + * 0x6 - WATCHed inbound frame + * 0x7 - (reserved for future use) + * + * An extended frame carries full MAC addressing, making it a + * superset of VERB_FRAME. It is used for bridged traffic, + * redirected or observed traffic via rules, and can in theory + * be used for multicast though MULTICAST_FRAME exists for that + * purpose and has additional options and capabilities. + * + * OK payload (if ACK flag is set): + * <[8] 64-bit network ID> + */ + VERB_EXT_FRAME = 0x07, - /** - * ECHO request (a.k.a. ping): - * <[...] arbitrary payload> - * - * This generates OK with a copy of the transmitted payload. No ERROR - * is generated. Response to ECHO requests is optional and ECHO may be - * ignored if a node detects a possible flood. - */ - VERB_ECHO = 0x08, + /** + * ECHO request (a.k.a. ping): + * <[...] arbitrary payload> + * + * This generates OK with a copy of the transmitted payload. No ERROR + * is generated. Response to ECHO requests is optional and ECHO may be + * ignored if a node detects a possible flood. + */ + VERB_ECHO = 0x08, - /** - * Announce interest in multicast group(s): - * <[8] 64-bit network ID> - * <[6] multicast Ethernet address> - * <[4] multicast additional distinguishing information (ADI)> - * [... additional tuples of network/address/adi ...] - * - * LIKEs may be sent to any peer, though a good implementation should - * restrict them to peers on the same network they're for and to network - * controllers and root servers. In the current network, root servers - * will provide the service of final multicast cache. - * - * VERB_NETWORK_CREDENTIALS should be pushed along with this, especially - * if using upstream (e.g. root) nodes as multicast databases. This allows - * GATHERs to be authenticated. - * - * OK/ERROR are not generated. - */ - VERB_MULTICAST_LIKE = 0x09, + /** + * Announce interest in multicast group(s): + * <[8] 64-bit network ID> + * <[6] multicast Ethernet address> + * <[4] multicast additional distinguishing information (ADI)> + * [... additional tuples of network/address/adi ...] + * + * LIKEs may be sent to any peer, though a good implementation should + * restrict them to peers on the same network they're for and to network + * controllers and root servers. In the current network, root servers + * will provide the service of final multicast cache. + * + * VERB_NETWORK_CREDENTIALS should be pushed along with this, especially + * if using upstream (e.g. root) nodes as multicast databases. This allows + * GATHERs to be authenticated. + * + * OK/ERROR are not generated. + */ + VERB_MULTICAST_LIKE = 0x09, - /** - * Network credentials push: - * [<[...] one or more certificates of membership>] - * <[1] 0x00, null byte marking end of COM array> - * <[2] 16-bit number of capabilities> - * <[...] one or more serialized Capability> - * <[2] 16-bit number of tags> - * <[...] one or more serialized Tags> - * <[2] 16-bit number of revocations> - * <[...] one or more serialized Revocations> - * <[2] 16-bit number of certificates of ownership> - * <[...] one or more serialized CertificateOfOwnership> - * - * This can be sent by anyone at any time to push network credentials. - * These will of course only be accepted if they are properly signed. - * Credentials can be for any number of networks. - * - * The use of a zero byte to terminate the COM section is for legacy - * backward compatibility. Newer fields are prefixed with a length. - * - * OK/ERROR are not generated. - */ - VERB_NETWORK_CREDENTIALS = 0x0a, + /** + * Network credentials push: + * [<[...] one or more certificates of membership>] + * <[1] 0x00, null byte marking end of COM array> + * <[2] 16-bit number of capabilities> + * <[...] one or more serialized Capability> + * <[2] 16-bit number of tags> + * <[...] one or more serialized Tags> + * <[2] 16-bit number of revocations> + * <[...] one or more serialized Revocations> + * <[2] 16-bit number of certificates of ownership> + * <[...] one or more serialized CertificateOfOwnership> + * + * This can be sent by anyone at any time to push network credentials. + * These will of course only be accepted if they are properly signed. + * Credentials can be for any number of networks. + * + * The use of a zero byte to terminate the COM section is for legacy + * backward compatibility. Newer fields are prefixed with a length. + * + * OK/ERROR are not generated. + */ + VERB_NETWORK_CREDENTIALS = 0x0a, - /** - * Network configuration request: - * <[8] 64-bit network ID> - * <[2] 16-bit length of request meta-data dictionary> - * <[...] string-serialized request meta-data> - * <[8] 64-bit revision of netconf we currently have> - * <[8] 64-bit timestamp of netconf we currently have> - * - * This message requests network configuration from a node capable of - * providing it. - * - * Responses to this are always whole configs intended for the recipient. - * For patches and other updates a NETWORK_CONFIG is sent instead. - * - * It would be valid and correct as of 1.2.0 to use NETWORK_CONFIG always, - * but OK(NETWORK_CONFIG_REQUEST) should be sent for compatibility. - * - * OK response payload: - * <[8] 64-bit network ID> - * <[2] 16-bit length of network configuration dictionary chunk> - * <[...] network configuration dictionary (may be incomplete)> - * [ ... end of legacy single chunk response ... ] - * <[1] 8-bit flags> - * <[8] 64-bit config update ID (should never be 0)> - * <[4] 32-bit total length of assembled dictionary> - * <[4] 32-bit index of chunk> - * [ ... end signed portion ... ] - * <[1] 8-bit chunk signature type> - * <[2] 16-bit length of chunk signature> - * <[...] chunk signature> - * - * The chunk signature signs the entire payload of the OK response. - * Currently only one signature type is supported: ed25519 (1). - * - * Each config chunk is signed to prevent memory exhaustion or - * traffic crowding DOS attacks against config fragment assembly. - * - * If the packet is from the network controller it is permitted to end - * before the config update ID or other chunking related or signature - * fields. This is to support older controllers that don't include - * these fields and may be removed in the future. - * - * ERROR response payload: - * <[8] 64-bit network ID> - * <[2] 16-bit length of error-related data (optional)> - * <[...] error-related data (optional)> - * - * Error related data is a Dictionary containing things like a URL - * for authentication or a human-readable error message, and is - * optional and may be absent or empty. - */ - VERB_NETWORK_CONFIG_REQUEST = 0x0b, + /** + * Network configuration request: + * <[8] 64-bit network ID> + * <[2] 16-bit length of request meta-data dictionary> + * <[...] string-serialized request meta-data> + * <[8] 64-bit revision of netconf we currently have> + * <[8] 64-bit timestamp of netconf we currently have> + * + * This message requests network configuration from a node capable of + * providing it. + * + * Responses to this are always whole configs intended for the recipient. + * For patches and other updates a NETWORK_CONFIG is sent instead. + * + * It would be valid and correct as of 1.2.0 to use NETWORK_CONFIG always, + * but OK(NETWORK_CONFIG_REQUEST) should be sent for compatibility. + * + * OK response payload: + * <[8] 64-bit network ID> + * <[2] 16-bit length of network configuration dictionary chunk> + * <[...] network configuration dictionary (may be incomplete)> + * [ ... end of legacy single chunk response ... ] + * <[1] 8-bit flags> + * <[8] 64-bit config update ID (should never be 0)> + * <[4] 32-bit total length of assembled dictionary> + * <[4] 32-bit index of chunk> + * [ ... end signed portion ... ] + * <[1] 8-bit chunk signature type> + * <[2] 16-bit length of chunk signature> + * <[...] chunk signature> + * + * The chunk signature signs the entire payload of the OK response. + * Currently only one signature type is supported: ed25519 (1). + * + * Each config chunk is signed to prevent memory exhaustion or + * traffic crowding DOS attacks against config fragment assembly. + * + * If the packet is from the network controller it is permitted to end + * before the config update ID or other chunking related or signature + * fields. This is to support older controllers that don't include + * these fields and may be removed in the future. + * + * ERROR response payload: + * <[8] 64-bit network ID> + * <[2] 16-bit length of error-related data (optional)> + * <[...] error-related data (optional)> + * + * Error related data is a Dictionary containing things like a URL + * for authentication or a human-readable error message, and is + * optional and may be absent or empty. + */ + VERB_NETWORK_CONFIG_REQUEST = 0x0b, - /** - * Network configuration data push: - * <[8] 64-bit network ID> - * <[2] 16-bit length of network configuration dictionary chunk> - * <[...] network configuration dictionary (may be incomplete)> - * <[1] 8-bit flags> - * <[8] 64-bit config update ID (should never be 0)> - * <[4] 32-bit total length of assembled dictionary> - * <[4] 32-bit index of chunk> - * [ ... end signed portion ... ] - * <[1] 8-bit chunk signature type> - * <[2] 16-bit length of chunk signature> - * <[...] chunk signature> - * - * This is a direct push variant for network config updates. It otherwise - * carries the same payload as OK(NETWORK_CONFIG_REQUEST) and has the same - * semantics. - * - * The legacy mode missing the additional chunking fields is not supported - * here. - * - * Flags: - * 0x01 - Use fast propagation - * - * An OK should be sent if the config is successfully received and - * accepted. - * - * OK payload: - * <[8] 64-bit network ID> - * <[8] 64-bit config update ID> - */ - VERB_NETWORK_CONFIG = 0x0c, + /** + * Network configuration data push: + * <[8] 64-bit network ID> + * <[2] 16-bit length of network configuration dictionary chunk> + * <[...] network configuration dictionary (may be incomplete)> + * <[1] 8-bit flags> + * <[8] 64-bit config update ID (should never be 0)> + * <[4] 32-bit total length of assembled dictionary> + * <[4] 32-bit index of chunk> + * [ ... end signed portion ... ] + * <[1] 8-bit chunk signature type> + * <[2] 16-bit length of chunk signature> + * <[...] chunk signature> + * + * This is a direct push variant for network config updates. It otherwise + * carries the same payload as OK(NETWORK_CONFIG_REQUEST) and has the same + * semantics. + * + * The legacy mode missing the additional chunking fields is not supported + * here. + * + * Flags: + * 0x01 - Use fast propagation + * + * An OK should be sent if the config is successfully received and + * accepted. + * + * OK payload: + * <[8] 64-bit network ID> + * <[8] 64-bit config update ID> + */ + VERB_NETWORK_CONFIG = 0x0c, - /** - * Request endpoints for multicast distribution: - * <[8] 64-bit network ID> - * <[1] flags> - * <[6] MAC address of multicast group being queried> - * <[4] 32-bit ADI for multicast group being queried> - * <[4] 32-bit requested max number of multicast peers> - * [<[...] network certificate of membership>] - * - * Flags: - * 0x01 - COM is attached - * - * This message asks a peer for additional known endpoints that have - * LIKEd a given multicast group. It's sent when the sender wishes - * to send multicast but does not have the desired number of recipient - * peers. - * - * More than one OK response can occur if the response is broken up across - * multiple packets or if querying a clustered node. - * - * The COM should be included so that upstream nodes that are not - * members of our network can validate our request. - * - * OK response payload: - * <[8] 64-bit network ID> - * <[6] MAC address of multicast group being queried> - * <[4] 32-bit ADI for multicast group being queried> - * [begin gather results -- these same fields can be in OK(MULTICAST_FRAME)] - * <[4] 32-bit total number of known members in this multicast group> - * <[2] 16-bit number of members enumerated in this packet> - * <[...] series of 5-byte ZeroTier addresses of enumerated members> - * - * ERROR is not generated; queries that return no response are dropped. - */ - VERB_MULTICAST_GATHER = 0x0d, + /** + * Request endpoints for multicast distribution: + * <[8] 64-bit network ID> + * <[1] flags> + * <[6] MAC address of multicast group being queried> + * <[4] 32-bit ADI for multicast group being queried> + * <[4] 32-bit requested max number of multicast peers> + * [<[...] network certificate of membership>] + * + * Flags: + * 0x01 - COM is attached + * + * This message asks a peer for additional known endpoints that have + * LIKEd a given multicast group. It's sent when the sender wishes + * to send multicast but does not have the desired number of recipient + * peers. + * + * More than one OK response can occur if the response is broken up across + * multiple packets or if querying a clustered node. + * + * The COM should be included so that upstream nodes that are not + * members of our network can validate our request. + * + * OK response payload: + * <[8] 64-bit network ID> + * <[6] MAC address of multicast group being queried> + * <[4] 32-bit ADI for multicast group being queried> + * [begin gather results -- these same fields can be in OK(MULTICAST_FRAME)] + * <[4] 32-bit total number of known members in this multicast group> + * <[2] 16-bit number of members enumerated in this packet> + * <[...] series of 5-byte ZeroTier addresses of enumerated members> + * + * ERROR is not generated; queries that return no response are dropped. + */ + VERB_MULTICAST_GATHER = 0x0d, - /** - * Multicast frame: - * <[8] 64-bit network ID> - * <[1] flags> - * [<[4] 32-bit implicit gather limit>] - * [<[6] source MAC>] - * <[6] destination MAC (multicast address)> - * <[4] 32-bit multicast ADI (multicast address extension)> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * Flags: - * 0x01 - Network certificate of membership attached (DEPRECATED) - * 0x02 - Implicit gather limit field is present - * 0x04 - Source MAC is specified -- otherwise it's computed from sender - * 0x08 - Please replicate (sent to multicast replicators) - * - * OK and ERROR responses are optional. OK may be generated if there are - * implicit gather results or if the recipient wants to send its own - * updated certificate of network membership to the sender. ERROR may be - * generated if a certificate is needed or if multicasts to this group - * are no longer wanted (multicast unsubscribe). - * - * OK response payload: - * <[8] 64-bit network ID> - * <[6] MAC address of multicast group> - * <[4] 32-bit ADI for multicast group> - * <[1] flags> - * [<[...] network certificate of membership (DEPRECATED)>] - * [<[...] implicit gather results if flag 0x01 is set>] - * - * OK flags (same bits as request flags): - * 0x01 - OK includes certificate of network membership (DEPRECATED) - * 0x02 - OK includes implicit gather results - * - * ERROR response payload: - * <[8] 64-bit network ID> - * <[6] multicast group MAC> - * <[4] 32-bit multicast group ADI> - */ - VERB_MULTICAST_FRAME = 0x0e, + /** + * Multicast frame: + * <[8] 64-bit network ID> + * <[1] flags> + * [<[4] 32-bit implicit gather limit>] + * [<[6] source MAC>] + * <[6] destination MAC (multicast address)> + * <[4] 32-bit multicast ADI (multicast address extension)> + * <[2] 16-bit ethertype> + * <[...] ethernet payload> + * + * Flags: + * 0x01 - Network certificate of membership attached (DEPRECATED) + * 0x02 - Implicit gather limit field is present + * 0x04 - Source MAC is specified -- otherwise it's computed from sender + * 0x08 - Please replicate (sent to multicast replicators) + * + * OK and ERROR responses are optional. OK may be generated if there are + * implicit gather results or if the recipient wants to send its own + * updated certificate of network membership to the sender. ERROR may be + * generated if a certificate is needed or if multicasts to this group + * are no longer wanted (multicast unsubscribe). + * + * OK response payload: + * <[8] 64-bit network ID> + * <[6] MAC address of multicast group> + * <[4] 32-bit ADI for multicast group> + * <[1] flags> + * [<[...] network certificate of membership (DEPRECATED)>] + * [<[...] implicit gather results if flag 0x01 is set>] + * + * OK flags (same bits as request flags): + * 0x01 - OK includes certificate of network membership (DEPRECATED) + * 0x02 - OK includes implicit gather results + * + * ERROR response payload: + * <[8] 64-bit network ID> + * <[6] multicast group MAC> + * <[4] 32-bit multicast group ADI> + */ + VERB_MULTICAST_FRAME = 0x0e, - /** - * Push of potential endpoints for direct communication: - * <[2] 16-bit number of paths> - * <[...] paths> - * - * Path record format: - * <[1] 8-bit path flags> - * <[2] length of extended path characteristics or 0 for none> - * <[...] extended path characteristics> - * <[1] address type> - * <[1] address length in bytes> - * <[...] address> - * - * Path record flags: - * 0x01 - Forget this path if currently known (not implemented yet) - * 0x02 - Cluster redirect -- use this in preference to others - * - * The receiver may, upon receiving a push, attempt to establish a - * direct link to one or more of the indicated addresses. It is the - * responsibility of the sender to limit which peers it pushes direct - * paths to to those with whom it has a trust relationship. The receiver - * must obey any restrictions provided such as exclusivity or blacklists. - * OK responses to this message are optional. - * - * Note that a direct path push does not imply that learned paths can't - * be used unless they are blacklisted explicitly or unless flag 0x01 - * is set. - * - * OK and ERROR are not generated. - */ - VERB_PUSH_DIRECT_PATHS = 0x10, + /** + * Push of potential endpoints for direct communication: + * <[2] 16-bit number of paths> + * <[...] paths> + * + * Path record format: + * <[1] 8-bit path flags> + * <[2] length of extended path characteristics or 0 for none> + * <[...] extended path characteristics> + * <[1] address type> + * <[1] address length in bytes> + * <[...] address> + * + * Path record flags: + * 0x01 - Forget this path if currently known (not implemented yet) + * 0x02 - Cluster redirect -- use this in preference to others + * + * The receiver may, upon receiving a push, attempt to establish a + * direct link to one or more of the indicated addresses. It is the + * responsibility of the sender to limit which peers it pushes direct + * paths to to those with whom it has a trust relationship. The receiver + * must obey any restrictions provided such as exclusivity or blacklists. + * OK responses to this message are optional. + * + * Note that a direct path push does not imply that learned paths can't + * be used unless they are blacklisted explicitly or unless flag 0x01 + * is set. + * + * OK and ERROR are not generated. + */ + VERB_PUSH_DIRECT_PATHS = 0x10, - // 0x11 -- deprecated + // 0x11 -- deprecated - /** - * An acknowledgment of receipt of a series of recent packets from another - * peer. This is used to calculate relative throughput values and to detect - * packet loss. Only VERB_FRAME and VERB_EXT_FRAME packets are counted. - * - * ACK response format: - * <[4] 32-bit number of bytes received since last ACK> - * - * Upon receipt of this packet, the local peer will verify that the correct - * number of bytes were received by the remote peer. If these values do - * not agree that could be an indication of packet loss. - * - * Additionally, the local peer knows the interval of time that has - * elapsed since the last received ACK. With this information it can compute - * a rough estimate of the current throughput. - * - * This is sent at a maximum rate of once per every ZT_QOS_ACK_INTERVAL - */ - VERB_ACK = 0x12, + /** + * An acknowledgment of receipt of a series of recent packets from another + * peer. This is used to calculate relative throughput values and to detect + * packet loss. Only VERB_FRAME and VERB_EXT_FRAME packets are counted. + * + * ACK response format: + * <[4] 32-bit number of bytes received since last ACK> + * + * Upon receipt of this packet, the local peer will verify that the correct + * number of bytes were received by the remote peer. If these values do + * not agree that could be an indication of packet loss. + * + * Additionally, the local peer knows the interval of time that has + * elapsed since the last received ACK. With this information it can compute + * a rough estimate of the current throughput. + * + * This is sent at a maximum rate of once per every ZT_QOS_ACK_INTERVAL + */ + VERB_ACK = 0x12, - /** - * A packet containing timing measurements useful for estimating path quality. - * Composed of a list of pairs for an - * arbitrary set of recent packets. This is used to sample for latency and - * packet delay variance (PDV, "jitter"). - * - * QoS record format: - * - * <[8] 64-bit packet ID of previously-received packet> - * <[1] 8-bit packet sojourn time> - * <...repeat until end of max 1400 byte packet...> - * - * The number of possible records per QoS packet is: (1400 * 8) / 72 = 155 - * This packet should be sent very rarely (every few seconds) as it can be - * somewhat large if the connection is saturated. Future versions might use - * a bloom table to probabilistically determine these values in a vastly - * more space-efficient manner. - * - * Note: The 'internal packet sojourn time' is a slight misnomer as it is a - * measure of the amount of time between when a packet was received and the - * egress time of its tracking QoS packet. - * - * This is sent at a maximum rate of once per every - * ZT_QOS_MEASUREMENT_INTERVAL - */ - VERB_QOS_MEASUREMENT = 0x13, + /** + * A packet containing timing measurements useful for estimating path quality. + * Composed of a list of pairs for an + * arbitrary set of recent packets. This is used to sample for latency and + * packet delay variance (PDV, "jitter"). + * + * QoS record format: + * + * <[8] 64-bit packet ID of previously-received packet> + * <[1] 8-bit packet sojourn time> + * <...repeat until end of max 1400 byte packet...> + * + * The number of possible records per QoS packet is: (1400 * 8) / 72 = 155 + * This packet should be sent very rarely (every few seconds) as it can be + * somewhat large if the connection is saturated. Future versions might use + * a bloom table to probabilistically determine these values in a vastly + * more space-efficient manner. + * + * Note: The 'internal packet sojourn time' is a slight misnomer as it is a + * measure of the amount of time between when a packet was received and the + * egress time of its tracking QoS packet. + * + * This is sent at a maximum rate of once per every + * ZT_QOS_MEASUREMENT_INTERVAL + */ + VERB_QOS_MEASUREMENT = 0x13, - /** - * A message with arbitrary user-definable content: - * <[8] 64-bit arbitrary message type ID> - * [<[...] message payload>] - * - * This can be used to send arbitrary messages over VL1. It generates no - * OK or ERROR and has no special semantics outside of whatever the user - * (via the ZeroTier core API) chooses to give it. - * - * Message type IDs less than or equal to 65535 are reserved for use by - * ZeroTier, Inc. itself. We recommend making up random ones for your own - * implementations. - */ - VERB_USER_MESSAGE = 0x14, + /** + * A message with arbitrary user-definable content: + * <[8] 64-bit arbitrary message type ID> + * [<[...] message payload>] + * + * This can be used to send arbitrary messages over VL1. It generates no + * OK or ERROR and has no special semantics outside of whatever the user + * (via the ZeroTier core API) chooses to give it. + * + * Message type IDs less than or equal to 65535 are reserved for use by + * ZeroTier, Inc. itself. We recommend making up random ones for your own + * implementations. + */ + VERB_USER_MESSAGE = 0x14, - /** - * A trace for remote debugging or diagnostics: - * <[...] null-terminated dictionary containing trace information> - * [<[...] additional null-terminated dictionaries>] - * - * This message contains a remote trace event. Remote trace events can - * be sent to observers configured at the network level for those that - * pertain directly to activity on a network, or to global observers if - * locally configured. - * - * The instance ID is a random 64-bit value generated by each ZeroTier - * node on startup. This is helpful in identifying traces from different - * members of a cluster. - */ - VERB_REMOTE_TRACE = 0x15, + /** + * A trace for remote debugging or diagnostics: + * <[...] null-terminated dictionary containing trace information> + * [<[...] additional null-terminated dictionaries>] + * + * This message contains a remote trace event. Remote trace events can + * be sent to observers configured at the network level for those that + * pertain directly to activity on a network, or to global observers if + * locally configured. + * + * The instance ID is a random 64-bit value generated by each ZeroTier + * node on startup. This is helpful in identifying traces from different + * members of a cluster. + */ + VERB_REMOTE_TRACE = 0x15, - /** - * A request to a peer to use a specific path in a multi-path scenario: - * <[2] 16-bit unsigned integer that encodes a path choice utility> - * - * This is sent when a node operating in multipath mode observes that - * its inbound and outbound traffic aren't going over the same path. The - * node will compute its perceived utility for using its chosen outbound - * path and send this to a peer in an attempt to petition it to send - * its traffic over this same path. - * - * Scenarios: - * - * (1) Remote peer utility is GREATER than ours: - * - Remote peer will refuse the petition and continue using current path - * (2) Remote peer utility is LESS than than ours: - * - Remote peer will accept the petition and switch to our chosen path - * (3) Remote peer utility is EQUAL to our own: - * - To prevent confusion and flapping, both side will agree to use the - * numerical values of their identities to determine which path to use. - * The peer with the greatest identity will win. - * - * If a node petitions a peer repeatedly with no effect it will regard - * that as a refusal by the remote peer, in this case if the utility is - * negligible it will voluntarily switch to the remote peer's chosen path. - */ - VERB_PATH_NEGOTIATION_REQUEST = 0x16 - }; + /** + * A request to a peer to use a specific path in a multi-path scenario: + * <[2] 16-bit unsigned integer that encodes a path choice utility> + * + * This is sent when a node operating in multipath mode observes that + * its inbound and outbound traffic aren't going over the same path. The + * node will compute its perceived utility for using its chosen outbound + * path and send this to a peer in an attempt to petition it to send + * its traffic over this same path. + * + * Scenarios: + * + * (1) Remote peer utility is GREATER than ours: + * - Remote peer will refuse the petition and continue using current path + * (2) Remote peer utility is LESS than than ours: + * - Remote peer will accept the petition and switch to our chosen path + * (3) Remote peer utility is EQUAL to our own: + * - To prevent confusion and flapping, both side will agree to use the + * numerical values of their identities to determine which path to use. + * The peer with the greatest identity will win. + * + * If a node petitions a peer repeatedly with no effect it will regard + * that as a refusal by the remote peer, in this case if the utility is + * negligible it will voluntarily switch to the remote peer's chosen path. + */ + VERB_PATH_NEGOTIATION_REQUEST = 0x16 + }; - /** - * Error codes for VERB_ERROR - */ - enum ErrorCode - { - /* No error, not actually used in transit */ - ERROR_NONE = 0x00, + /** + * Error codes for VERB_ERROR + */ + enum ErrorCode + { + /* No error, not actually used in transit */ + ERROR_NONE = 0x00, - /* Invalid request */ - ERROR_INVALID_REQUEST = 0x01, + /* Invalid request */ + ERROR_INVALID_REQUEST = 0x01, - /* Bad/unsupported protocol version */ - ERROR_BAD_PROTOCOL_VERSION = 0x02, + /* Bad/unsupported protocol version */ + ERROR_BAD_PROTOCOL_VERSION = 0x02, - /* Unknown object queried */ - ERROR_OBJ_NOT_FOUND = 0x03, + /* Unknown object queried */ + ERROR_OBJ_NOT_FOUND = 0x03, - /* HELLO pushed an identity whose address is already claimed */ - ERROR_IDENTITY_COLLISION = 0x04, + /* HELLO pushed an identity whose address is already claimed */ + ERROR_IDENTITY_COLLISION = 0x04, - /* Verb or use case not supported/enabled by this node */ - ERROR_UNSUPPORTED_OPERATION = 0x05, + /* Verb or use case not supported/enabled by this node */ + ERROR_UNSUPPORTED_OPERATION = 0x05, - /* Network membership certificate update needed */ - ERROR_NEED_MEMBERSHIP_CERTIFICATE = 0x06, + /* Network membership certificate update needed */ + ERROR_NEED_MEMBERSHIP_CERTIFICATE = 0x06, - /* Tried to join network, but you're not a member */ - ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */ + /* Tried to join network, but you're not a member */ + ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */ - /* Multicasts to this group are not wanted */ - ERROR_UNWANTED_MULTICAST = 0x08, + /* Multicasts to this group are not wanted */ + ERROR_UNWANTED_MULTICAST = 0x08, /* Network requires external or 2FA authentication (e.g. SSO). */ ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09 - }; + }; - template - Packet(const Buffer &b) : - Buffer(b) - { - } + template + Packet(const Buffer &b) : + Buffer(b) + { + } - Packet(const void *data,unsigned int len) : - Buffer(data,len) - { - } + Packet(const void *data,unsigned int len) : + Buffer(data,len) + { + } - /** - * Construct a new empty packet with a unique random packet ID - * - * Flags and hops will be zero. Other fields and data region are undefined. - * Use the header access methods (setDestination() and friends) to fill out - * the header. Payload should be appended; initial size is header size. - */ - Packet() : - Buffer(ZT_PROTO_MIN_PACKET_LENGTH) - { - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops - } + /** + * Construct a new empty packet with a unique random packet ID + * + * Flags and hops will be zero. Other fields and data region are undefined. + * Use the header access methods (setDestination() and friends) to fill out + * the header. Payload should be appended; initial size is header size. + */ + Packet() : + Buffer(ZT_PROTO_MIN_PACKET_LENGTH) + { + Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); + (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops + } - /** - * Make a copy of a packet with a new initialization vector and destination address - * - * This can be used to take one draft prototype packet and quickly make copies to - * encrypt for different destinations. - * - * @param prototype Prototype packet - * @param dest Destination ZeroTier address for new packet - */ - Packet(const Packet &prototype,const Address &dest) : - Buffer(prototype) - { - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - setDestination(dest); - } + /** + * Make a copy of a packet with a new initialization vector and destination address + * + * This can be used to take one draft prototype packet and quickly make copies to + * encrypt for different destinations. + * + * @param prototype Prototype packet + * @param dest Destination ZeroTier address for new packet + */ + Packet(const Packet &prototype,const Address &dest) : + Buffer(prototype) + { + Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); + setDestination(dest); + } - /** - * Construct a new empty packet with a unique random packet ID - * - * @param dest Destination ZT address - * @param source Source ZT address - * @param v Verb - */ - Packet(const Address &dest,const Address &source,const Verb v) : - Buffer(ZT_PROTO_MIN_PACKET_LENGTH) - { - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - setDestination(dest); - setSource(source); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops - setVerb(v); - } + /** + * Construct a new empty packet with a unique random packet ID + * + * @param dest Destination ZT address + * @param source Source ZT address + * @param v Verb + */ + Packet(const Address &dest,const Address &source,const Verb v) : + Buffer(ZT_PROTO_MIN_PACKET_LENGTH) + { + Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); + setDestination(dest); + setSource(source); + (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops + setVerb(v); + } - /** - * Reset this packet structure for reuse in place - * - * @param dest Destination ZT address - * @param source Source ZT address - * @param v Verb - */ - inline void reset(const Address &dest,const Address &source,const Verb v) - { - setSize(ZT_PROTO_MIN_PACKET_LENGTH); - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - setDestination(dest); - setSource(source); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops - setVerb(v); - } + /** + * Reset this packet structure for reuse in place + * + * @param dest Destination ZT address + * @param source Source ZT address + * @param v Verb + */ + inline void reset(const Address &dest,const Address &source,const Verb v) + { + setSize(ZT_PROTO_MIN_PACKET_LENGTH); + Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); + setDestination(dest); + setSource(source); + (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops + setVerb(v); + } - /** - * Generate a new IV / packet ID in place - * - * This can be used to re-use a packet buffer multiple times to send - * technically different but otherwise identical copies of the same - * packet. - */ - inline void newInitializationVector() { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); } + /** + * Generate a new IV / packet ID in place + * + * This can be used to re-use a packet buffer multiple times to send + * technically different but otherwise identical copies of the same + * packet. + */ + inline void newInitializationVector() { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); } - /** - * Set this packet's destination - * - * @param dest ZeroTier address of destination - */ - inline void setDestination(const Address &dest) { dest.copyTo(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } + /** + * Set this packet's destination + * + * @param dest ZeroTier address of destination + */ + inline void setDestination(const Address &dest) { dest.copyTo(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - /** - * Set this packet's source - * - * @param source ZeroTier address of source - */ - inline void setSource(const Address &source) { source.copyTo(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } + /** + * Set this packet's source + * + * @param source ZeroTier address of source + */ + inline void setSource(const Address &source) { source.copyTo(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - /** - * Get this packet's destination - * - * @return Destination ZT address - */ - inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } + /** + * Get this packet's destination + * + * @return Destination ZT address + */ + inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - /** - * Get this packet's source - * - * @return Source ZT address - */ - inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } + /** + * Get this packet's source + * + * @return Source ZT address + */ + inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - /** - * @return True if packet is of valid length - */ - inline bool lengthValid() const { return (size() >= ZT_PROTO_MIN_PACKET_LENGTH); } + /** + * @return True if packet is of valid length + */ + inline bool lengthValid() const { return (size() >= ZT_PROTO_MIN_PACKET_LENGTH); } - /** - * @return True if packet is fragmented (expect fragments) - */ - inline bool fragmented() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0); } + /** + * @return True if packet is fragmented (expect fragments) + */ + inline bool fragmented() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0); } - /** - * Set this packet's fragmented flag - * - * @param f Fragmented flag value - */ - inline void setFragmented(bool f) - { - if (f) { - (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED; - } else { - (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED); - } - } + /** + * Set this packet's fragmented flag + * + * @param f Fragmented flag value + */ + inline void setFragmented(bool f) + { + if (f) { + (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED; + } else { + (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED); + } + } - /** - * @return True if compressed (result only valid if unencrypted) - */ - inline bool compressed() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0); } + /** + * @return True if compressed (result only valid if unencrypted) + */ + inline bool compressed() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0); } - /** - * @return ZeroTier forwarding hops (0 to 7) - */ - inline unsigned int hops() const { return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07); } + /** + * @return ZeroTier forwarding hops (0 to 7) + */ + inline unsigned int hops() const { return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07); } - /** - * Increment this packet's hop count - */ - inline void incrementHops() - { - unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; - b = (b & 0xf8) | ((b + 1) & 0x07); - } + /** + * Increment this packet's hop count + */ + inline void incrementHops() + { + unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; + b = (b & 0xf8) | ((b + 1) & 0x07); + } - /** - * @return Cipher suite selector: 0 - 7 (see #defines) - */ - inline unsigned int cipher() const - { - return (((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x38) >> 3); - } + /** + * @return Cipher suite selector: 0 - 7 (see #defines) + */ + inline unsigned int cipher() const + { + return (((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x38) >> 3); + } - /** - * @return Whether this packet is currently encrypted - */ - inline bool isEncrypted() const - { - return (cipher() == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) || (cipher() == ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV); - } + /** + * @return Whether this packet is currently encrypted + */ + inline bool isEncrypted() const + { + return (cipher() == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) || (cipher() == ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV); + } - /** - * Set this packet's cipher suite - */ - inline void setCipher(unsigned int c) - { - unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; - b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH - } + /** + * Set this packet's cipher suite + */ + inline void setCipher(unsigned int c) + { + unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; + b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH + } - /** - * Get the trusted path ID for this packet (only meaningful if cipher is trusted path) - * - * @return Trusted path ID (from MAC field) - */ - inline uint64_t trustedPathId() const { return at(ZT_PACKET_IDX_MAC); } + /** + * Get the trusted path ID for this packet (only meaningful if cipher is trusted path) + * + * @return Trusted path ID (from MAC field) + */ + inline uint64_t trustedPathId() const { return at(ZT_PACKET_IDX_MAC); } - /** - * Set this packet's trusted path ID and set the cipher spec to trusted path - * - * @param tpid Trusted path ID - */ - inline void setTrusted(const uint64_t tpid) - { - setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH); - setAt(ZT_PACKET_IDX_MAC,tpid); - } + /** + * Set this packet's trusted path ID and set the cipher spec to trusted path + * + * @param tpid Trusted path ID + */ + inline void setTrusted(const uint64_t tpid) + { + setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH); + setAt(ZT_PACKET_IDX_MAC,tpid); + } - /** - * Get this packet's unique ID (the IV field interpreted as uint64_t) - * - * Note that the least significant 3 bits of this ID will change when armor() - * is called to armor the packet for transport. This is because armor() will - * mask the last 3 bits against the send counter for QoS monitoring use prior - * to actually using the IV to encrypt and MAC the packet. Be aware of this - * when grabbing the packetId of a new packet prior to armor/send. - * - * @return Packet ID - */ - inline uint64_t packetId() const { return at(ZT_PACKET_IDX_IV); } + /** + * Get this packet's unique ID (the IV field interpreted as uint64_t) + * + * Note that the least significant 3 bits of this ID will change when armor() + * is called to armor the packet for transport. This is because armor() will + * mask the last 3 bits against the send counter for QoS monitoring use prior + * to actually using the IV to encrypt and MAC the packet. Be aware of this + * when grabbing the packetId of a new packet prior to armor/send. + * + * @return Packet ID + */ + inline uint64_t packetId() const { return at(ZT_PACKET_IDX_IV); } - /** - * Set packet verb - * - * This also has the side-effect of clearing any verb flags, such as - * compressed, and so must only be done during packet composition. - * - * @param v New packet verb - */ - inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; } + /** + * Set packet verb + * + * This also has the side-effect of clearing any verb flags, such as + * compressed, and so must only be done during packet composition. + * + * @param v New packet verb + */ + inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; } - /** - * @return Packet verb (not including flag bits) - */ - inline Verb verb() const { return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f); } + /** + * @return Packet verb (not including flag bits) + */ + inline Verb verb() const { return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f); } - /** - * @return Length of packet payload - */ - inline unsigned int payloadLength() const { return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH)); } + /** + * @return Length of packet payload + */ + inline unsigned int payloadLength() const { return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH)); } - /** - * @return Raw packet payload - */ - inline const unsigned char *payload() const { return field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); } + /** + * @return Raw packet payload + */ + inline const unsigned char *payload() const { return field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); } - /** - * Armor packet for transport - * - * @param key 32-byte key - * @param encryptPayload If true, encrypt packet payload, else just MAC - * @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV - */ - void armor(const void *key,bool encryptPayload,bool extendedArmor,const AES aesKeys[2],const Identity &identity); + /** + * Armor packet for transport + * + * @param key 32-byte key + * @param encryptPayload If true, encrypt packet payload, else just MAC + * @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV + */ + void armor(const void *key,bool encryptPayload,bool extendedArmor,const AES aesKeys[2],const Identity &identity); - /** - * Verify and (if encrypted) decrypt packet - * - * This does not handle trusted path mode packets and will return false - * for these. These are handled in IncomingPacket if the sending physical - * address and MAC field match a trusted path. - * - * @param key 32-byte key - * @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV - * @return False if packet is invalid or failed MAC authenticity check - */ - bool dearmor(const void *key,const AES aesKeys[2],const Identity &identity); + /** + * Verify and (if encrypted) decrypt packet + * + * This does not handle trusted path mode packets and will return false + * for these. These are handled in IncomingPacket if the sending physical + * address and MAC field match a trusted path. + * + * @param key 32-byte key + * @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV + * @return False if packet is invalid or failed MAC authenticity check + */ + bool dearmor(const void *key,const AES aesKeys[2],const Identity &identity); - /** - * Encrypt/decrypt a separately armored portion of a packet - * - * This is currently only used to mask portions of HELLO as an extra - * security precaution since most of that message is sent in the clear. - * - * This must NEVER be used more than once in the same packet, as doing - * so will result in re-use of the same key stream. - * - * @param key 32-byte key - * @param start Start of encrypted portion - * @param len Length of encrypted portion - */ - void cryptField(const void *key,unsigned int start,unsigned int len); + /** + * Encrypt/decrypt a separately armored portion of a packet + * + * This is currently only used to mask portions of HELLO as an extra + * security precaution since most of that message is sent in the clear. + * + * This must NEVER be used more than once in the same packet, as doing + * so will result in re-use of the same key stream. + * + * @param key 32-byte key + * @param start Start of encrypted portion + * @param len Length of encrypted portion + */ + void cryptField(const void *key,unsigned int start,unsigned int len); - /** - * Attempt to compress payload if not already (must be unencrypted) - * - * This requires that the payload at least contain the verb byte already - * set. The compressed flag in the verb is set if compression successfully - * results in a size reduction. If no size reduction occurs, compression - * is not done and the flag is left cleared. - * - * @return True if compression occurred - */ - bool compress(); + /** + * Attempt to compress payload if not already (must be unencrypted) + * + * This requires that the payload at least contain the verb byte already + * set. The compressed flag in the verb is set if compression successfully + * results in a size reduction. If no size reduction occurs, compression + * is not done and the flag is left cleared. + * + * @return True if compression occurred + */ + bool compress(); - /** - * Attempt to decompress payload if it is compressed (must be unencrypted) - * - * If payload is compressed, it is decompressed and the compressed verb - * flag is cleared. Otherwise nothing is done and true is returned. - * - * @return True if data is now decompressed and valid, false on error - */ - bool uncompress(); + /** + * Attempt to decompress payload if it is compressed (must be unencrypted) + * + * If payload is compressed, it is decompressed and the compressed verb + * flag is cleared. Otherwise nothing is done and true is returned. + * + * @return True if data is now decompressed and valid, false on error + */ + bool uncompress(); private: - static const unsigned char ZERO_KEY[32]; + static const unsigned char ZERO_KEY[32]; - /** - * Deterministically mangle a 256-bit crypto key based on packet - * - * This uses extra data from the packet to mangle the secret, giving us an - * effective IV that is somewhat more than 64 bits. This is "free" for - * Salsa20 since it has negligible key setup time so using a different - * key each time is fine. - * - * @param in Input key (32 bytes) - * @param out Output buffer (32 bytes) - */ - inline void _salsa20MangleKey(const unsigned char *in,unsigned char *out) const - { - const unsigned char *d = (const unsigned char *)data(); + /** + * Deterministically mangle a 256-bit crypto key based on packet + * + * This uses extra data from the packet to mangle the secret, giving us an + * effective IV that is somewhat more than 64 bits. This is "free" for + * Salsa20 since it has negligible key setup time so using a different + * key each time is fine. + * + * @param in Input key (32 bytes) + * @param out Output buffer (32 bytes) + */ + inline void _salsa20MangleKey(const unsigned char *in,unsigned char *out) const + { + const unsigned char *d = (const unsigned char *)data(); - // IV and source/destination addresses. Using the addresses divides the - // key space into two halves-- A->B and B->A (since order will change). - for(unsigned int i=0;i<18;++i) { // 8 + (ZT_ADDRESS_LENGTH * 2) == 18 - out[i] = in[i] ^ d[i]; - } + // IV and source/destination addresses. Using the addresses divides the + // key space into two halves-- A->B and B->A (since order will change). + for(unsigned int i=0;i<18;++i) { // 8 + (ZT_ADDRESS_LENGTH * 2) == 18 + out[i] = in[i] ^ d[i]; + } - // Flags, but with hop count masked off. Hop count is altered by forwarding - // nodes. It's one of the only parts of a packet modifiable by people - // without the key. - out[18] = in[18] ^ (d[ZT_PACKET_IDX_FLAGS] & 0xf8); + // Flags, but with hop count masked off. Hop count is altered by forwarding + // nodes. It's one of the only parts of a packet modifiable by people + // without the key. + out[18] = in[18] ^ (d[ZT_PACKET_IDX_FLAGS] & 0xf8); - // Raw packet size in bytes -- thus each packet size defines a new - // key space. - out[19] = in[19] ^ (unsigned char)(size() & 0xff); - out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian + // Raw packet size in bytes -- thus each packet size defines a new + // key space. + out[19] = in[19] ^ (unsigned char)(size() & 0xff); + out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian - // Rest of raw key is used unchanged - for(unsigned int i=21;i<32;++i) { - out[i] = in[i]; - } - } + // Rest of raw key is used unchanged + for(unsigned int i=21;i<32;++i) { + out[i] = in[i]; + } + } }; } // namespace ZeroTier