mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
Reorg.
This commit is contained in:
parent
03bcdf74a8
commit
d3cf7b2202
141 changed files with 20058 additions and 32571 deletions
|
@ -102,7 +102,6 @@ endif()
|
|||
add_subdirectory(node)
|
||||
add_subdirectory(controller)
|
||||
add_subdirectory(osdep)
|
||||
#add_subdirectory(root)
|
||||
add_subdirectory(go/native)
|
||||
|
||||
#if(BUILD_CENTRAL_CONTROLLER)
|
||||
|
|
176
attic/BP.hpp
176
attic/BP.hpp
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#ifndef ZT_BP_HPP
|
||||
#define ZT_BP_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* A C-like pointer to a byte array with static bounds checking whenever possible.
|
||||
*
|
||||
* This fills the niche in between Buf and a naked C pointer and behaves like a C pointer
|
||||
* annotated with a length that is statically checked at compile time. It should have no
|
||||
* runtime overhead at all.
|
||||
*
|
||||
* - Explicit or implicit casts are supported to pointers to smaller but not larger arrays
|
||||
* - A templated slice() method (analogous to Go slices) allows getting subset arrays
|
||||
* - A templated at() method allows bounds checked access to indices known at compile time
|
||||
* - Copy and assignment from larger or equal sized arrays, but not smaller
|
||||
* - NULL pointers are explicitly not allowed, so a naked pointer must still be used in that case
|
||||
*
|
||||
* Note that the [] operator for dynamic access is NOT bounds checked as this would add
|
||||
* runtime overhead that is not desirable where this is used. The goal here is to keep
|
||||
* C performance while being safer to the extent that C++ allows.
|
||||
*
|
||||
* @tparam S Size of memory to which this pointer must point
|
||||
*/
|
||||
template<unsigned int S>
|
||||
class BP
|
||||
{
|
||||
public:
|
||||
typedef uint8_t * iterator;
|
||||
typedef const uint8_t * const_iterator;
|
||||
|
||||
explicit ZT_INLINE BP(void *const bytes) : p(reinterpret_cast<uint8_t *>(bytes)) {}
|
||||
|
||||
template<unsigned int CS>
|
||||
ZT_INLINE BP(BP<CS> &b) noexcept :
|
||||
p(b.p)
|
||||
{
|
||||
static_assert(CS <= S,"attempt to copy byte pointer from one of smaller size");
|
||||
}
|
||||
|
||||
template<unsigned int CS>
|
||||
ZT_INLINE BP &operator=(BP<CS> &b)
|
||||
{
|
||||
static_assert(CS <= S,"attempt to assign byte pointer from one of smaller size");
|
||||
p = b.p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned int CS>
|
||||
ZT_INLINE operator BP<CS>() noexcept // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
{
|
||||
static_assert(CS <= S,"attempt to cast byte pointer to larger size");
|
||||
return BP<CS>(p);
|
||||
}
|
||||
|
||||
ZT_INLINE uint8_t &operator[](const unsigned int i) noexcept
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
ZT_INLINE uint8_t operator[](const unsigned int i) const noexcept
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
template<typename I>
|
||||
ZT_INLINE uint8_t *operator+(const I i) noexcept
|
||||
{
|
||||
return p + i;
|
||||
}
|
||||
template<typename I>
|
||||
ZT_INLINE const uint8_t *operator+(const I i) const noexcept
|
||||
{
|
||||
return p + i;
|
||||
}
|
||||
|
||||
ZT_INLINE uint8_t &operator*() noexcept
|
||||
{
|
||||
static_assert(S > 0,"attempt to access empty array");
|
||||
return *p;
|
||||
}
|
||||
ZT_INLINE uint8_t operator*() const noexcept
|
||||
{
|
||||
static_assert(S > 0,"attempt to access empty array");
|
||||
return *p;
|
||||
}
|
||||
|
||||
template<unsigned int I>
|
||||
ZT_INLINE uint8_t &at() noexcept
|
||||
{
|
||||
static_assert(I < S,"static access beyond end of byte pointer");
|
||||
return p[I];
|
||||
}
|
||||
template<unsigned int I>
|
||||
ZT_INLINE uint8_t at() const noexcept
|
||||
{
|
||||
static_assert(I < S,"static access beyond end of byte pointer");
|
||||
return p[I];
|
||||
}
|
||||
|
||||
template<unsigned int RS,unsigned int RE>
|
||||
ZT_INLINE BP<RE - RS> &slice() noexcept
|
||||
{
|
||||
static_assert(RE > RS,"slice must end after it begins");
|
||||
static_assert(RE <= S,"slice ends after byte array end");
|
||||
return reinterpret_cast< BP<RE - RS> >(*this);
|
||||
}
|
||||
|
||||
template<unsigned int RS,unsigned int RE>
|
||||
ZT_INLINE const BP<RE - RS> &slice() const noexcept
|
||||
{
|
||||
static_assert(RE > RS,"slice must end after it begins");
|
||||
static_assert(RE <= S,"slice ends after byte array end");
|
||||
return reinterpret_cast< BP<RE - RS> >(*this);
|
||||
}
|
||||
|
||||
template<unsigned int F>
|
||||
ZT_INLINE BP<S - F> &from() noexcept
|
||||
{
|
||||
static_assert(F < S,"attempt to get array from beyond bounds");
|
||||
return reinterpret_cast< BP<S - F> >(*this);
|
||||
}
|
||||
template<unsigned int F>
|
||||
ZT_INLINE const BP<S - F> &from() const noexcept
|
||||
{
|
||||
static_assert(F < S,"attempt to get array from beyond bounds");
|
||||
return reinterpret_cast< BP<S - F> >(*this);
|
||||
}
|
||||
|
||||
ZT_INLINE iterator begin() noexcept { return p; }
|
||||
ZT_INLINE iterator end() noexcept { return p + S; }
|
||||
ZT_INLINE const_iterator begin() const noexcept { return p; }
|
||||
ZT_INLINE const_iterator end() const noexcept { return p + S; }
|
||||
|
||||
static constexpr unsigned int size() noexcept { return S; }
|
||||
|
||||
template<unsigned int CS>
|
||||
ZT_INLINE bool operator==(const BP<CS> &b) const noexcept { return p == b.p; }
|
||||
template<unsigned int CS>
|
||||
ZT_INLINE bool operator!=(const BP<CS> &b) const noexcept { return p != b.p; }
|
||||
template<unsigned int CS>
|
||||
ZT_INLINE bool operator<(const BP<CS> &b) const noexcept { return p < b.p; }
|
||||
template<unsigned int CS>
|
||||
ZT_INLINE bool operator>(const BP<CS> &b) const noexcept { return p > b.p; }
|
||||
template<unsigned int CS>
|
||||
ZT_INLINE bool operator<=(const BP<CS> &b) const noexcept { return p <= b.p; }
|
||||
template<unsigned int CS>
|
||||
ZT_INLINE bool operator>=(const BP<CS> &b) const noexcept { return p >= b.p; }
|
||||
|
||||
ZT_INLINE bool operator==(const void *const b) const noexcept { return p == reinterpret_cast<const uint8_t *>(b); }
|
||||
ZT_INLINE bool operator!=(const void *const b) const noexcept { return p != reinterpret_cast<const uint8_t *>(b); }
|
||||
ZT_INLINE bool operator<(const void *const b) const noexcept { return p < reinterpret_cast<const uint8_t *>(b); }
|
||||
ZT_INLINE bool operator>(const void *const b) const noexcept { return p > reinterpret_cast<const uint8_t *>(b); }
|
||||
ZT_INLINE bool operator<=(const void *const b) const noexcept { return p <= reinterpret_cast<const uint8_t *>(b); }
|
||||
ZT_INLINE bool operator>=(const void *const b) const noexcept { return p >= reinterpret_cast<const uint8_t *>(b); }
|
||||
|
||||
private:
|
||||
uint8_t *const p;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
|
@ -1,638 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
#include "GoGlue.h"
|
||||
|
||||
#include "../../node/Constants.hpp"
|
||||
#include "../../node/InetAddress.hpp"
|
||||
#include "../../node/Utils.hpp"
|
||||
#include "../../node/Identity.hpp"
|
||||
#include "../../node/Salsa20.hpp"
|
||||
#include "../../node/Dictionary.hpp"
|
||||
#include "../../node/SHA512.hpp"
|
||||
#include "../../node/C25519.hpp"
|
||||
#include "../../node/ECC384.hpp"
|
||||
#include "../../node/Poly1305.hpp"
|
||||
|
||||
#include "../../osdep/OSUtils.hpp"
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
using namespace ZeroTier;
|
||||
|
||||
static volatile uint8_t foo = 0;
|
||||
|
||||
#define KNOWN_GOOD_IDENTITY_0 "8e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e"
|
||||
#define KNOWN_BAD_IDENTITY_0 "9e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e"
|
||||
|
||||
// These were generated with some Go code using the NIST P-384 elliptic curve. There
|
||||
// are official P-384 test vectors but the format of these is funny and converting is
|
||||
// a pain, so this is easier. We assume the Go runtime's P-384 implementation is correct.
|
||||
#define ECC384_TEST_PUBLIC "02edbcbb1f239bbd9d3d7cef6b37a32669e94df42664fbac7640c22221a6a3df8c9681760f0e67abd45158b31563fb4971"
|
||||
#define ECC384_TEST_PRIVATE "62939b4a293cc68698c3d07fb7ff97a2fbc9368a1da5408e4913d41546cbb408fa8cb27fcc3f72f80d167bf0a4c329d3"
|
||||
#define ECC384_TEST_DH_SELF_AGREE "f696bd1bda5e528c1d56a36ed9bad784dd201b50c9d868b9529327ab17edc6ae895e7fd9461587f4c8472ef786f5870b"
|
||||
#define ECC384_TEST_SIG "98935f0a052cba3ad7d208de64e7772cbde6d91611d2ef03ba129f1498498c2d3650d9cfbb2beacb28e70b90439e018b52db46ecc7f6a95688003cdb4ffe04a1c74c3ffcb8c8704212f437facdb9172f608cb605c6ce37d6c9f00b233910290d"
|
||||
|
||||
static const unsigned char s20TV0Key[32] = { 0x0f,0x62,0xb5,0x08,0x5b,0xae,0x01,0x54,0xa7,0xfa,0x4d,0xa0,0xf3,0x46,0x99,0xec,0x3f,0x92,0xe5,0x38,0x8b,0xde,0x31,0x84,0xd7,0x2a,0x7d,0xd0,0x23,0x76,0xc9,0x1c };
|
||||
static const unsigned char s20TV0Iv[8] = { 0x28,0x8f,0xf6,0x5d,0xc4,0x2b,0x92,0xf9 };
|
||||
static const unsigned char s20TV0Ks[64] = { 0x5e,0x5e,0x71,0xf9,0x01,0x99,0x34,0x03,0x04,0xab,0xb2,0x2a,0x37,0xb6,0x62,0x5b,0xf8,0x83,0xfb,0x89,0xce,0x3b,0x21,0xf5,0x4a,0x10,0xb8,0x10,0x66,0xef,0x87,0xda,0x30,0xb7,0x76,0x99,0xaa,0x73,0x79,0xda,0x59,0x5c,0x77,0xdd,0x59,0x54,0x2d,0xa2,0x08,0xe5,0x95,0x4f,0x89,0xe4,0x0e,0xb7,0xaa,0x80,0xa8,0x4a,0x61,0x76,0x66,0x3f };
|
||||
|
||||
static const unsigned char s2012TV0Key[32] = { 0x0f,0x62,0xb5,0x08,0x5b,0xae,0x01,0x54,0xa7,0xfa,0x4d,0xa0,0xf3,0x46,0x99,0xec,0x3f,0x92,0xe5,0x38,0x8b,0xde,0x31,0x84,0xd7,0x2a,0x7d,0xd0,0x23,0x76,0xc9,0x1c };
|
||||
static const unsigned char s2012TV0Iv[8] = { 0x28,0x8f,0xf6,0x5d,0xc4,0x2b,0x92,0xf9 };
|
||||
static const unsigned char s2012TV0Ks[64] = { 0x99,0xDB,0x33,0xAD,0x11,0xCE,0x0C,0xCB,0x3B,0xFD,0xBF,0x8D,0x0C,0x18,0x16,0x04,0x52,0xD0,0x14,0xCD,0xE9,0x89,0xB4,0xC4,0x11,0xA5,0x59,0xFF,0x7C,0x20,0xA1,0x69,0xE6,0xDC,0x99,0x09,0xD8,0x16,0xBE,0xCE,0xDC,0x40,0x63,0xCE,0x07,0xCE,0xA8,0x28,0xF4,0x4B,0xF9,0xB6,0xC9,0xA0,0xA0,0xB2,0x00,0xE1,0xB5,0x2A,0xF4,0x18,0x59,0xC5 };
|
||||
|
||||
static const unsigned char poly1305TV0Input[32] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
|
||||
static const unsigned char poly1305TV0Key[32] = { 0x74,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x33,0x32,0x2d,0x62,0x79,0x74,0x65,0x20,0x6b,0x65,0x79,0x20,0x66,0x6f,0x72,0x20,0x50,0x6f,0x6c,0x79,0x31,0x33,0x30,0x35 };
|
||||
static const unsigned char poly1305TV0Tag[16] = { 0x49,0xec,0x78,0x09,0x0e,0x48,0x1e,0xc6,0xc2,0x6b,0x33,0xb9,0x1c,0xcc,0x03,0x07 };
|
||||
|
||||
static const unsigned char poly1305TV1Input[12] = { 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x77,0x6f,0x72,0x6c,0x64,0x21 };
|
||||
static const unsigned char poly1305TV1Key[32] = { 0x74,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x33,0x32,0x2d,0x62,0x79,0x74,0x65,0x20,0x6b,0x65,0x79,0x20,0x66,0x6f,0x72,0x20,0x50,0x6f,0x6c,0x79,0x31,0x33,0x30,0x35 };
|
||||
static const unsigned char poly1305TV1Tag[16] = { 0xa6,0xf7,0x45,0x00,0x8f,0x81,0xc9,0x16,0xa2,0x0d,0xcc,0x74,0xee,0xf2,0xb2,0xf0 };
|
||||
|
||||
static const char *sha512TV0Input = "supercalifragilisticexpealidocious";
|
||||
static const unsigned char sha512TV0Digest[64] = { 0x18,0x2a,0x85,0x59,0x69,0xe5,0xd3,0xe6,0xcb,0xf6,0x05,0x24,0xad,0xf2,0x88,0xd1,0xbb,0xf2,0x52,0x92,0x81,0x24,0x31,0xf6,0xd2,0x52,0xf1,0xdb,0xc1,0xcb,0x44,0xdf,0x21,0x57,0x3d,0xe1,0xb0,0x6b,0x68,0x75,0x95,0x9f,0x3b,0x6f,0x87,0xb1,0x13,0x81,0xd0,0xbc,0x79,0x2c,0x43,0x3a,0x13,0x55,0x3c,0xe0,0x84,0xc2,0x92,0x55,0x31,0x1c };
|
||||
static const unsigned char sha384TV0Digest[48] = { 0x71,0xe7,0x71,0x79,0xae,0xc3,0xf3,0x5f,0x93,0xea,0xe2,0x1d,0xe3,0x3f,0x24,0x6d,0xed,0x2a,0x59,0xae,0x22,0x45,0x27,0x6c,0x12,0x57,0xf3,0xbe,0xe6,0xce,0xe2,0x73,0xd8,0xad,0xaa,0x9b,0x99,0xa4,0x8a,0x1b,0x7a,0xb9,0x5d,0xfb,0x9c,0x1a,0x1c,0xf6 };
|
||||
|
||||
struct C25519TestVector
|
||||
{
|
||||
unsigned char pub1[64];
|
||||
unsigned char priv1[64];
|
||||
unsigned char pub2[64];
|
||||
unsigned char priv2[64];
|
||||
unsigned char agreement[64];
|
||||
unsigned char agreementSignedBy1[96];
|
||||
unsigned char agreementSignedBy2[96];
|
||||
};
|
||||
|
||||
#define ZT_NUM_C25519_TEST_VECTORS 32
|
||||
|
||||
static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] = {
|
||||
{{0xa1,0xfc,0x7a,0xb4,0x6d,0xdf,0x7d,0xcf,0xe7,0xec,0x75,0xe5,0xfa,0xdd,0x11,0xcb,0xcc,0x37,0xf8,0x84,0x5d,0x1c,0x92,0x4e,0x09,0x89,0x65,0xfc,0xd8,0xe9,0x5a,0x30,0xda,0xe4,0x86,0xa3,0x35,0xb4,0x19,0x0c,0xbc,0x7b,0xcb,0x3e,0xb9,0x4c,0xbd,0x16,0xe8,0x3d,0x13,0x2b,0xc9,0xc3,0x39,0xea,0xf1,0x42,0xe7,0x6f,0x69,0x78,0x9a,0xb7},{0xe5,0xf3,0x7b,0xd4,0x0e,0xc9,0xdc,0x77,0x50,0x86,0xdc,0xf4,0x2e,0xbc,0xdb,0x27,0xf0,0x73,0xd4,0x58,0x73,0xc4,0x4b,0x71,0x8b,0x3c,0xc5,0x4f,0xa8,0x7c,0xa4,0x84,0xd9,0x96,0x23,0x73,0xb4,0x03,0x16,0xbf,0x1e,0xa1,0x2d,0xd8,0xc4,0x8a,0xe7,0x82,0x10,0xda,0xc9,0xe5,0x45,0x9b,0x01,0xdc,0x73,0xa6,0xc9,0x17,0xa8,0x15,0x31,0x6d},{0x3e,0x49,0xa4,0x0e,0x3a,0xaf,0xa3,0x07,0x3d,0xf7,0x2a,0xec,0x43,0xb1,0xd4,0x09,0x1a,0xcb,0x8e,0x92,0xf9,0x65,0x95,0x04,0x6d,0x2d,0x9b,0x34,0xa3,0xbf,0x51,0x00,0xe2,0xee,0x23,0xf5,0x28,0x0a,0xa9,0xb1,0x57,0x0b,0x96,0x56,0x62,0xba,0x12,0x94,0xaf,0xc6,0x5f,0xb5,0x61,0x43,0x0f,0xde,0x0b,0xab,0xfa,0x4f,0xfe,0xc5,0xe7,0x18},{0x00,0x4d,0x41,0x8d,0xe4,0x69,0x23,0xae,0x98,0xc4,0x3e,0x77,0x0f,0x1d,0x94,0x5d,0x29,0x3e,0x94,0x5a,0x38,0x39,0x20,0x0f,0xd3,0x6f,0x76,0xa2,0x29,0x02,0x03,0xcb,0x0b,0x7f,0x4f,0x1a,0x29,0x51,0x13,0x33,0x7c,0x99,0xb3,0x81,0x82,0x39,0x44,0x05,0x97,0xfb,0x0d,0xf2,0x93,0xa2,0x40,0x94,0xf4,0xff,0x5d,0x09,0x61,0xe4,0x5f,0x76},{0xab,0xce,0xd2,0x24,0xe8,0x93,0xb0,0xe7,0x72,0x14,0xdc,0xbb,0x7d,0x0f,0xd8,0x94,0x16,0x9e,0xb5,0x7f,0xd7,0x19,0x5f,0x3e,0x2d,0x45,0xd5,0xf7,0x90,0x0b,0x3e,0x05,0x18,0x2e,0x2b,0xf4,0xfa,0xd4,0xec,0x62,0x4a,0x4f,0x48,0x50,0xaf,0x1c,0xe8,0x9f,0x1a,0xe1,0x3d,0x70,0x49,0x00,0xa7,0xe3,0x5b,0x1e,0xa1,0x9b,0x68,0x1e,0xa1,0x73},{0xed,0xb6,0xd0,0xf0,0x06,0x6e,0x33,0x9c,0x86,0xfb,0xe8,0xc3,0x6c,0x8d,0xde,0xdd,0xa6,0xa0,0x2d,0xb9,0x07,0x29,0xa3,0x13,0xbb,0xa4,0xba,0xec,0x48,0xc8,0xf4,0x56,0x82,0x79,0xe2,0xb1,0xd3,0x3d,0x83,0x9f,0x10,0xe8,0x52,0xe6,0x8b,0x1c,0x33,0x9e,0x2b,0xd2,0xdb,0x62,0x1c,0x56,0xfd,0x50,0x40,0x77,0x81,0xab,0x21,0x67,0x3e,0x09,0x4f,0xf2,0x51,0xac,0x7d,0xe7,0xd1,0x5d,0x4b,0xe2,0x08,0xc6,0x3f,0x6a,0x4d,0xc8,0x5d,0x74,0xf6,0x3b,0xec,0x8e,0xc6,0x0c,0x32,0x27,0x2f,0x9c,0x09,0x48,0x59,0x10},{0x23,0x0f,0xa3,0xe2,0x69,0xce,0xb9,0xb9,0xd1,0x1c,0x4e,0xab,0x63,0xc9,0x2e,0x1e,0x7e,0xa2,0xa2,0xa0,0x49,0x2e,0x78,0xe4,0x8a,0x02,0x3b,0xa7,0xab,0x1f,0xd4,0xce,0x05,0xe2,0x80,0x09,0x09,0x3c,0x61,0xc7,0x10,0x3a,0x9c,0xf4,0x95,0xac,0x89,0x6f,0x23,0xb3,0x09,0xe2,0x24,0x3f,0xf6,0x96,0x02,0x36,0x41,0x16,0x32,0xe1,0x66,0x05,0x4f,0xf2,0x51,0xac,0x7d,0xe7,0xd1,0x5d,0x4b,0xe2,0x08,0xc6,0x3f,0x6a,0x4d,0xc8,0x5d,0x74,0xf6,0x3b,0xec,0x8e,0xc6,0x0c,0x32,0x27,0x2f,0x9c,0x09,0x48,0x59,0x10}},
|
||||
{{0xfd,0x81,0x14,0xf1,0x67,0x07,0x44,0xbb,0x93,0x84,0xa2,0xdc,0x36,0xdc,0xcc,0xb3,0x9e,0x82,0xd4,0x8b,0x42,0x56,0xfb,0xf2,0x6e,0x83,0x3b,0x16,0x2c,0x29,0xfb,0x39,0x29,0x48,0x85,0xe3,0xe3,0xf7,0xe7,0x80,0x49,0xd3,0x01,0x30,0x5a,0x2c,0x3f,0x4c,0xea,0x13,0xeb,0xda,0xf4,0x56,0x75,0x8d,0x50,0x1e,0x19,0x2d,0x29,0x2b,0xfb,0xdb},{0x85,0x34,0x4d,0xf7,0x39,0xbf,0x98,0x79,0x8c,0x98,0xeb,0x8d,0x61,0x27,0xec,0x87,0x56,0xcd,0xd0,0xa6,0x55,0x77,0xee,0xf0,0x20,0xd0,0x59,0x39,0x95,0xab,0x29,0x82,0x8e,0x61,0xf8,0xad,0xed,0xb6,0x27,0xc3,0xd8,0x16,0xce,0x67,0x78,0xe2,0x04,0x4b,0x0c,0x2d,0x2f,0xc3,0x24,0x72,0xbc,0x53,0xbd,0xfe,0x39,0x23,0xd4,0xaf,0x27,0x84},{0x11,0xbe,0x5f,0x5a,0x73,0xe7,0x42,0xef,0xff,0x3c,0x47,0x6a,0x0e,0x6b,0x9e,0x96,0x21,0xa3,0xdf,0x49,0xe9,0x3f,0x40,0xfc,0xab,0xb3,0x66,0xd3,0x3d,0xfa,0x02,0x29,0xf3,0x43,0x45,0x3c,0x70,0xa3,0x5d,0x39,0xf7,0xc0,0x6a,0xcd,0xfa,0x1d,0xbe,0x3b,0x91,0x41,0xe4,0xb0,0x60,0xc0,0x22,0xf7,0x2c,0x11,0x2b,0x1c,0x5f,0x24,0xef,0x53},{0xfd,0x3f,0x09,0x06,0xc9,0x39,0x8d,0x48,0xfa,0x6b,0xc9,0x80,0xbf,0xf6,0xd6,0x76,0xb3,0x62,0x70,0x88,0x4f,0xde,0xde,0xb9,0xb4,0xf0,0xce,0xf3,0x74,0x0d,0xea,0x00,0x9e,0x9c,0x29,0xe1,0xa2,0x1b,0xbd,0xb5,0x83,0xcc,0x12,0xd8,0x48,0x08,0x5b,0xe5,0xd6,0xf9,0x11,0x5c,0xe0,0xd9,0xc3,0x3c,0x26,0xbd,0x69,0x9f,0x5c,0x6f,0x0c,0x6f},{0xca,0xd4,0x76,0x32,0x8b,0xbe,0x0c,0x65,0x75,0x43,0x73,0xc2,0xf2,0xfd,0x7f,0xeb,0xe4,0x62,0xc5,0x0d,0x0f,0xf9,0x01,0xc8,0xb9,0xfa,0xca,0xb4,0x12,0x1c,0xb4,0xac,0x0e,0x5f,0x18,0xfc,0x0c,0x7f,0x2a,0x55,0xc5,0xfd,0x4d,0x83,0xb2,0x02,0x31,0x6a,0x3f,0x14,0xee,0x9d,0x11,0xa8,0x06,0xad,0xeb,0x93,0x19,0x79,0xb1,0xf2,0x78,0x05},{0x85,0xe6,0xe2,0xf2,0x96,0xe7,0xa2,0x8b,0x7e,0x36,0xbd,0x7b,0xf4,0x28,0x6a,0xd7,0xbc,0x2a,0x6a,0x59,0xfd,0xc0,0xc8,0x3d,0x50,0x0f,0x0c,0x2b,0x12,0x3a,0x75,0xc7,0x56,0xbb,0x7f,0x7d,0x4e,0xd4,0x03,0xb8,0x7b,0xde,0xde,0x99,0x65,0x9e,0xc4,0xa6,0x6e,0xfe,0x00,0x88,0xeb,0x9d,0xa4,0xa9,0x9d,0x37,0xc9,0x4a,0xcf,0x69,0xc4,0x01,0xba,0xa8,0xce,0xeb,0x72,0xcb,0x64,0x8b,0x9f,0xc1,0x1f,0x9a,0x9e,0x99,0xcc,0x39,0xec,0xd9,0xbb,0xd9,0xce,0xc2,0x74,0x6f,0xd0,0x2a,0xb9,0xc6,0xe3,0xf5,0xe7,0xf4},{0xb1,0x39,0x50,0xb1,0x1a,0x08,0x42,0x2b,0xdd,0x6d,0x20,0x9f,0x0f,0x37,0xba,0x69,0x97,0x21,0x30,0x7a,0x71,0x2f,0xce,0x98,0x09,0x04,0xa2,0x98,0x6a,0xed,0x02,0x1d,0x5d,0x30,0x8f,0x03,0x47,0x6b,0x89,0xfd,0xf7,0x1a,0xca,0x46,0x6f,0x51,0x69,0x9a,0x2b,0x18,0x77,0xe4,0xad,0x0d,0x7a,0x66,0xd2,0x2c,0x28,0xa0,0xd3,0x0a,0x99,0x0d,0xba,0xa8,0xce,0xeb,0x72,0xcb,0x64,0x8b,0x9f,0xc1,0x1f,0x9a,0x9e,0x99,0xcc,0x39,0xec,0xd9,0xbb,0xd9,0xce,0xc2,0x74,0x6f,0xd0,0x2a,0xb9,0xc6,0xe3,0xf5,0xe7,0xf4}},
|
||||
{{0x02,0x3a,0x7e,0x0c,0x6d,0x96,0x3c,0x5d,0x44,0x56,0x5d,0xc1,0x49,0x94,0x35,0x12,0x9d,0xff,0x8a,0x5d,0x91,0x74,0xa8,0x15,0xee,0x5d,0x1e,0x72,0xbe,0x86,0x15,0x68,0xe7,0x36,0xa2,0x4a,0xb8,0xa2,0xa4,0x4c,0xd8,0x95,0xe3,0xc7,0xbb,0x32,0x21,0x90,0x64,0x52,0x32,0xeb,0x26,0xd3,0x4f,0xf0,0x8e,0x27,0x40,0xea,0xed,0xdb,0xf5,0xc4},{0x76,0x99,0x64,0x70,0xf4,0x50,0xc8,0xcc,0x4a,0x5a,0xa5,0x0f,0xeb,0x2d,0xc7,0x0e,0x73,0xd0,0x65,0x7d,0xc3,0xce,0x73,0x03,0x20,0x2f,0xad,0x65,0xfd,0x12,0xe4,0x7f,0xfd,0x45,0x3a,0x6e,0xc5,0x9a,0x06,0x67,0x0e,0xa6,0x7b,0x21,0x49,0x2d,0x01,0x1b,0x8e,0x03,0x6e,0x10,0x08,0x0c,0x68,0xd9,0x60,0x47,0xa4,0xe2,0x52,0xfd,0x3c,0xf4},{0xa3,0xe2,0x5f,0x16,0x39,0x78,0x96,0xf7,0x47,0x6f,0x93,0x5d,0x27,0x7b,0x58,0xe0,0xc5,0xdb,0x71,0x7d,0xa9,0x6f,0xf8,0x8b,0x69,0xdd,0x50,0xea,0x91,0x0d,0x66,0x77,0xaf,0x8f,0xd5,0x9f,0x8a,0x26,0x69,0x4c,0x64,0x37,0x62,0x81,0x6f,0x05,0x9a,0x08,0x0d,0xe1,0x69,0x24,0x77,0x3f,0x50,0xb2,0x49,0x4d,0x93,0xef,0x2e,0x87,0xff,0xde},{0xb3,0x32,0xe2,0x67,0x79,0x32,0x5f,0x64,0x47,0x49,0x1c,0xd3,0x8f,0x95,0x44,0xfd,0x4c,0x7e,0xbf,0x6b,0xb7,0xaf,0x2c,0xdd,0x8f,0xa5,0xd8,0x2f,0xbf,0xa0,0x8a,0x6b,0x58,0x25,0xc9,0x12,0x23,0x6f,0xe6,0x05,0xa8,0xd0,0x68,0x6e,0x0c,0xee,0x70,0xe4,0xa3,0x86,0x51,0x04,0x6d,0xca,0xd5,0xed,0xcf,0x74,0x1d,0x60,0x9e,0x86,0x2d,0x05},{0x91,0xf4,0x5f,0x4a,0xcb,0xd8,0xfd,0x5f,0xb9,0x3d,0x04,0xb8,0xec,0x35,0x85,0x4f,0x58,0x20,0xd1,0x1f,0x47,0xc4,0xf4,0xcb,0x21,0x4e,0x9a,0xf1,0x6e,0xbf,0xe3,0xd3,0x62,0xe3,0x82,0xf6,0xba,0xa8,0xdf,0x92,0xe2,0x3c,0xe5,0xf0,0x16,0x8a,0xeb,0xa4,0xbb,0xc7,0x81,0xaf,0x15,0x19,0x87,0x5f,0xb7,0xe0,0x4c,0x12,0xff,0x2c,0xa9,0xc8},{0xaf,0x85,0xe0,0x36,0x43,0xdf,0x41,0x17,0xda,0xde,0x5e,0xb6,0x33,0xd0,0xce,0x62,0x70,0x5f,0x85,0x24,0x6c,0x3e,0x1b,0xe1,0x52,0xc1,0x9b,0x1c,0xcd,0x61,0x80,0x9c,0xa0,0xe8,0x18,0xee,0x40,0x91,0x93,0x82,0xdb,0x33,0x44,0xff,0xd4,0xf6,0x6f,0x5d,0xf0,0x0e,0x92,0x92,0x81,0x55,0x46,0x06,0xac,0x58,0x81,0x3b,0x04,0xc7,0xf7,0x0d,0xd2,0x0c,0x08,0x6d,0x46,0xdb,0x43,0x28,0x31,0xd8,0xcd,0x87,0x50,0xbb,0xd3,0x07,0xf5,0x72,0x0b,0x15,0x7c,0x16,0xab,0x03,0xd9,0x4b,0x07,0x38,0x97,0xe8,0xd6,0xb5},{0x93,0xff,0x6d,0xc3,0x62,0xf7,0xcc,0x20,0x95,0xc2,0x2f,0x7d,0x1d,0x9b,0xd1,0x63,0xfc,0x61,0x47,0xb3,0x22,0x0f,0xca,0xb0,0x16,0xcf,0x29,0x53,0x46,0x97,0xb1,0x36,0x46,0xac,0x48,0x13,0x92,0xe4,0x46,0x68,0xcf,0x09,0x4e,0xfa,0x59,0x45,0x24,0x08,0xdb,0xb4,0x6f,0x20,0x55,0x12,0xd9,0x75,0x9d,0x8e,0x0b,0xf8,0x63,0xe0,0xf9,0x01,0xd2,0x0c,0x08,0x6d,0x46,0xdb,0x43,0x28,0x31,0xd8,0xcd,0x87,0x50,0xbb,0xd3,0x07,0xf5,0x72,0x0b,0x15,0x7c,0x16,0xab,0x03,0xd9,0x4b,0x07,0x38,0x97,0xe8,0xd6,0xb5}},
|
||||
{{0x14,0x35,0xa6,0x7d,0xc1,0xb5,0x71,0xca,0x42,0x50,0x90,0xa7,0x72,0x85,0xbe,0x78,0x7a,0x5f,0x83,0x1e,0xbe,0xef,0x6a,0xbe,0x48,0xc5,0x68,0x14,0x0c,0xf7,0x44,0x5c,0x2e,0xfd,0x1b,0xcc,0xee,0x09,0x23,0x82,0x31,0xad,0xaf,0x4b,0x73,0x9c,0xf2,0x88,0x3c,0xf3,0xb5,0x43,0x8b,0x53,0xf9,0xac,0x17,0x86,0x1c,0xc2,0x53,0x43,0xec,0x03},{0x7b,0x36,0x6c,0xcc,0xb5,0xb2,0x23,0x3d,0x7c,0xe5,0xe7,0xcf,0x06,0xe2,0x32,0x0b,0xc5,0x3b,0x7f,0x86,0x40,0xfc,0xaf,0xba,0x94,0xe0,0x88,0x58,0x5b,0xac,0xe8,0xc3,0xe8,0xc3,0xdf,0xc4,0x45,0x29,0xe8,0xf0,0x1c,0x10,0x0d,0x50,0x81,0x29,0x30,0xa8,0x27,0xb5,0x3e,0xb8,0x25,0xf1,0x17,0x30,0xc6,0x05,0xe3,0x3e,0x45,0x38,0xa8,0x3c},{0xce,0xd9,0x45,0x28,0xb0,0xce,0xa5,0x47,0xa8,0x29,0x32,0x76,0x99,0x73,0x8d,0x74,0xf9,0xed,0x0a,0xd0,0xf1,0xd8,0x7e,0x44,0x63,0x9e,0x9a,0xcf,0x7c,0x35,0x8a,0x29,0xbb,0x71,0x66,0x8d,0xa7,0xfc,0x05,0x3d,0xd4,0x4b,0x65,0x20,0xf5,0xa4,0x64,0xd8,0x9d,0x16,0x80,0x9c,0xb2,0x3c,0x3e,0xd4,0x9d,0x09,0x88,0x8e,0xbb,0x58,0xf8,0x77},{0xe1,0x29,0xb3,0x16,0xe6,0xa0,0xdb,0x64,0x08,0x36,0xdc,0x33,0xad,0x8b,0x30,0x26,0x17,0x56,0xd7,0x34,0x17,0xd1,0xdd,0x23,0x38,0x58,0x25,0x01,0x42,0x5a,0x9d,0x18,0x3e,0xac,0x31,0xfa,0x43,0x28,0xc4,0x65,0xfb,0x30,0x2f,0x8c,0x16,0x52,0x32,0x1b,0x19,0xb7,0x31,0xf6,0x67,0xa7,0xd8,0xed,0x9a,0xa3,0x95,0x01,0xd7,0xb9,0xe7,0xcc},{0x81,0x2d,0x11,0xa9,0x11,0xf1,0x22,0xe2,0x67,0x70,0xc4,0xba,0x34,0xa1,0x75,0x8c,0xf6,0x0c,0x63,0xe7,0x01,0x3c,0x64,0x6c,0xe8,0xd0,0xf8,0x8e,0x88,0xdf,0x5c,0x61,0x68,0x5d,0x1f,0xeb,0x83,0x1f,0x40,0xb8,0xa8,0x56,0x57,0x26,0x81,0x2c,0xa3,0x0e,0x48,0x4c,0x45,0x4d,0x0d,0x3d,0x6e,0x99,0x52,0xbd,0x0b,0xd8,0x05,0xc5,0xf9,0x61},{0x92,0x45,0xbe,0xe6,0xb4,0x7a,0xfa,0x28,0xd4,0x5b,0x6b,0x17,0xc6,0x13,0x61,0x5d,0x5f,0xd7,0x90,0xbb,0x89,0x35,0x7a,0x02,0x50,0x57,0x56,0x5f,0x19,0xb5,0xb6,0xc5,0x77,0x1e,0x1b,0xc0,0xd7,0x7a,0x29,0xbd,0xe7,0x24,0x01,0x2d,0x37,0xc0,0x38,0x6f,0xc8,0x35,0xa1,0x1b,0xe0,0xea,0x16,0xad,0xbc,0xdc,0xd4,0x8d,0x4e,0x71,0xdb,0x05,0x9e,0xb5,0x53,0x6b,0x5c,0xf1,0x7d,0x15,0x8b,0xd7,0xc7,0x8b,0x89,0x9d,0xfd,0x28,0x7c,0xa1,0x31,0xe2,0xf0,0x2c,0x3a,0x8d,0x0e,0x23,0x85,0x4e,0xf0,0xd1,0xc0,0x83},{0x7b,0x88,0xeb,0x45,0x1c,0x7f,0xfd,0xbe,0xba,0xac,0x53,0x28,0x59,0xe8,0xad,0x28,0xf1,0x97,0x2d,0x6c,0x31,0xa6,0xae,0x47,0x10,0x69,0x68,0x55,0xa6,0x9c,0x03,0x62,0xb7,0x2f,0x31,0x46,0x2a,0x2b,0x98,0xdd,0xe9,0xf9,0xfe,0x77,0x71,0x41,0x54,0xf8,0x59,0x02,0x7a,0xe3,0x45,0x67,0xb6,0xf7,0x94,0x31,0x3e,0x62,0x62,0x2a,0xf9,0x0a,0x9e,0xb5,0x53,0x6b,0x5c,0xf1,0x7d,0x15,0x8b,0xd7,0xc7,0x8b,0x89,0x9d,0xfd,0x28,0x7c,0xa1,0x31,0xe2,0xf0,0x2c,0x3a,0x8d,0x0e,0x23,0x85,0x4e,0xf0,0xd1,0xc0,0x83}},
|
||||
{{0x27,0x4d,0x84,0x08,0x95,0x84,0xc8,0xeb,0x1c,0x9a,0x0f,0xca,0x09,0x6f,0x48,0x8b,0x2b,0x06,0xa0,0xae,0xf2,0xe3,0x8a,0xfe,0xd7,0x52,0x4b,0xf2,0xc6,0x7c,0xc1,0x55,0x87,0x2e,0x5a,0xb4,0xc2,0x43,0x0a,0x0d,0xd0,0x00,0xa8,0xe1,0x46,0x68,0x79,0xd8,0x8c,0x01,0x36,0xb7,0x5a,0x61,0x04,0xe9,0x7e,0xbb,0xc9,0xee,0xaa,0x12,0x13,0xda},{0x78,0x66,0xd0,0xa2,0x50,0x82,0x8d,0xb0,0xa0,0x20,0xac,0xa4,0xb6,0xa0,0x31,0xf7,0x7d,0x93,0x37,0x67,0xbb,0x60,0xa2,0x1e,0x36,0xce,0x3d,0x48,0x1d,0x79,0x99,0xa5,0x19,0xd8,0x89,0x1b,0xcb,0x14,0x87,0xb7,0x62,0xfd,0xd2,0xef,0xbb,0x13,0x41,0x4d,0xf1,0x77,0x5c,0x7f,0x6c,0x3b,0x94,0x7d,0xb4,0xba,0x87,0x3e,0xc8,0xe1,0x3c,0x0a},{0xd9,0x9e,0x14,0x89,0xd6,0xf8,0x49,0xa2,0xe2,0x19,0xfe,0x94,0xaa,0xf7,0x35,0xf9,0x4a,0xf8,0xf3,0x18,0x68,0x96,0x47,0xc6,0x23,0x7c,0xb0,0x53,0xcb,0xd8,0x90,0x31,0xb7,0x50,0x0e,0x06,0xc3,0x84,0x75,0xf1,0xac,0x16,0x4d,0xc1,0xbe,0xf1,0x80,0x33,0x47,0x56,0x6f,0x33,0x94,0x5c,0x81,0x03,0x4c,0x2f,0x6d,0xac,0x73,0xba,0x91,0x3c},{0x2f,0xa9,0xb6,0xe8,0x73,0xe2,0xef,0x6d,0x6d,0xd7,0x2e,0xa0,0x51,0x61,0x24,0x81,0x8c,0xa8,0x47,0x40,0xe1,0xc7,0x75,0x79,0xc8,0xec,0xb2,0x23,0x41,0xad,0x61,0x3b,0xea,0x8a,0xdf,0x63,0xed,0xe1,0x8e,0x50,0x70,0x6e,0x86,0xed,0xb0,0xba,0x27,0x48,0x8e,0xb9,0x63,0x39,0x78,0x58,0x4f,0x1e,0xbc,0x45,0xf3,0xf2,0x3a,0x73,0x9b,0x8c},{0xad,0x42,0xc5,0x84,0xca,0xe1,0xe1,0x23,0x2a,0x73,0x15,0x3c,0x9a,0xfe,0x85,0x8d,0xa3,0x2c,0xcf,0x46,0x8d,0x7f,0x1c,0x61,0xd7,0x0e,0xb1,0xa6,0xb4,0xae,0xab,0x63,0xc4,0x0e,0xf2,0xa0,0x5d,0xa6,0xf3,0x5d,0x35,0x41,0xea,0x03,0x91,0xb1,0x3a,0x07,0xe6,0xed,0x6c,0x8c,0xcb,0x75,0x27,0xf1,0x26,0x58,0xf0,0x62,0x57,0xe4,0x33,0x00},{0x1f,0xed,0x53,0xc6,0xef,0x38,0x26,0xa4,0x18,0x88,0x8f,0x5c,0x49,0x1c,0x15,0x7d,0x77,0x90,0x06,0x39,0xe0,0x7c,0x25,0xed,0x79,0x05,0x66,0xe0,0x5e,0x94,0xe3,0x46,0x6f,0x96,0xd8,0xc1,0x11,0xa4,0x11,0x6f,0x78,0x42,0x8e,0x89,0xc7,0xc3,0xed,0xd2,0x9e,0x68,0x47,0x79,0x89,0x23,0x70,0x14,0x21,0x60,0x2d,0xfe,0x37,0x4b,0xc8,0x0a,0x16,0x73,0x7c,0xc4,0x55,0x3f,0x25,0x04,0x08,0x75,0x74,0x68,0xbc,0xe4,0x3a,0xae,0x4c,0x0e,0xd2,0x85,0xa1,0xbc,0x81,0xc0,0xc9,0xfe,0x9a,0x44,0x7b,0x83,0xdf,0xc7},{0x27,0x77,0x97,0x84,0x0f,0x2d,0x8d,0x33,0xb8,0x4e,0xdb,0x8b,0xea,0x58,0x52,0x88,0x95,0x88,0x55,0x5f,0xb8,0xc4,0xc9,0xd6,0x1f,0x1e,0xee,0x60,0xb5,0xeb,0x78,0x72,0xb5,0xe5,0x22,0x2b,0x7f,0x5e,0xc7,0x9b,0x29,0x55,0x8e,0x2a,0xfc,0x65,0x55,0x4a,0x02,0xad,0x64,0x06,0xd4,0x25,0xe1,0x96,0x6f,0xee,0x96,0xcd,0x29,0xc6,0x64,0x00,0x16,0x73,0x7c,0xc4,0x55,0x3f,0x25,0x04,0x08,0x75,0x74,0x68,0xbc,0xe4,0x3a,0xae,0x4c,0x0e,0xd2,0x85,0xa1,0xbc,0x81,0xc0,0xc9,0xfe,0x9a,0x44,0x7b,0x83,0xdf,0xc7}},
|
||||
{{0x5e,0xc5,0x5b,0x9c,0xdb,0x14,0x05,0x18,0x6b,0xe2,0x1d,0x16,0x77,0x22,0x0e,0xd2,0xe4,0x57,0x82,0x6e,0x5b,0xc5,0x6a,0xb9,0x34,0x20,0xdb,0x72,0xe2,0xe1,0xeb,0x1b,0x34,0x00,0x04,0xbf,0x83,0xf6,0x4f,0x12,0x45,0x08,0xf0,0x95,0x2a,0xdc,0x3a,0x14,0xb3,0x29,0x0b,0x99,0xcd,0x73,0x31,0xbd,0x04,0xbb,0x49,0x1c,0xde,0xcf,0x09,0x9e},{0x15,0x80,0x3e,0x2a,0xfb,0xc0,0x8d,0x62,0x19,0x27,0x83,0x04,0xcc,0xf5,0xd1,0xbb,0x40,0x41,0xbe,0x93,0x59,0x6e,0x27,0x6d,0x95,0x24,0x0a,0x07,0x27,0x86,0x10,0x75,0xf7,0x0a,0x11,0xfc,0x53,0xd0,0x4c,0x15,0xf8,0x6e,0x22,0x3f,0xeb,0x12,0x97,0x8a,0x3d,0x69,0xd8,0x96,0xc9,0x53,0x10,0x9c,0x02,0x95,0xe4,0xd3,0x1a,0xd5,0x43,0x82},{0x40,0x09,0x2c,0x17,0x7e,0xba,0xce,0x1f,0xfc,0xc1,0x8e,0xc3,0x1c,0xa2,0x34,0x52,0x78,0x16,0x23,0x71,0x82,0x40,0xf8,0x6d,0x67,0x65,0x67,0x50,0x53,0xd9,0xc8,0x5e,0x7e,0x8a,0x98,0xa3,0xc6,0x2a,0x4d,0x27,0xf3,0xb9,0xbb,0xae,0x43,0x29,0x6e,0x02,0x1c,0xe9,0x01,0xd6,0xcd,0xd8,0x91,0x44,0x95,0x2b,0x9e,0xa5,0x4f,0xd0,0x00,0xb9},{0x3a,0xe8,0x3d,0xb3,0x32,0xdc,0xc2,0xc8,0xe3,0x36,0x2f,0xc9,0x30,0x3a,0xc0,0x76,0x56,0xd3,0x0b,0x06,0xbe,0x8f,0xe7,0xf1,0x66,0x61,0x25,0x42,0x28,0xdc,0x08,0x81,0x84,0x3a,0x57,0x96,0x27,0xa6,0xcf,0xd6,0x8f,0x35,0xa2,0xc3,0x76,0x86,0x4f,0xcf,0x5f,0xa1,0x85,0x28,0x4f,0x4a,0x3a,0xbb,0x5c,0x25,0x4b,0xcc,0x46,0xfe,0xf2,0x04},{0x62,0xc8,0xa2,0x0a,0x59,0xb8,0x97,0xd2,0x68,0x94,0x00,0x3b,0x01,0xac,0x91,0x6e,0x97,0x8e,0x08,0xe3,0xfe,0x9f,0x9e,0x9f,0x4b,0xcc,0x5d,0x1d,0xb9,0xbf,0x07,0x83,0xfe,0x51,0x2a,0xdf,0x79,0x2e,0x07,0xc9,0x98,0x9b,0xbe,0xb6,0xe4,0x0a,0x20,0x44,0x86,0xea,0xb1,0x61,0x58,0x11,0x32,0x8e,0x7b,0xb9,0x67,0x2d,0xf0,0x78,0xb2,0x93},{0x1a,0x65,0xb3,0x6f,0xa2,0x45,0x29,0x53,0xd7,0x23,0x4d,0xff,0x8e,0xe9,0xb9,0xef,0x16,0xa0,0xdd,0x48,0xdf,0x70,0xd2,0xe1,0x56,0xca,0xd1,0xd0,0x4a,0x9d,0x63,0x92,0x2b,0xfd,0x7b,0x87,0x39,0x3c,0x12,0xc7,0xe5,0x91,0x31,0x95,0x78,0xc4,0x58,0x95,0x89,0x6e,0x2c,0x90,0xb4,0x0b,0xb2,0xfe,0x52,0xc0,0x86,0xc4,0x2e,0x56,0x97,0x0c,0x20,0xf2,0xbc,0x6a,0x9b,0x89,0xfb,0xe9,0x85,0x95,0xd6,0x22,0x5e,0x4d,0x6d,0x83,0x9d,0xf4,0xbe,0x66,0x05,0x32,0xb6,0xe2,0xf1,0x96,0x42,0xa4,0xc8,0x8c,0x1b,0xec},{0x43,0x85,0xff,0xb9,0xcf,0x04,0x83,0x40,0x70,0x3a,0x9c,0x48,0xb4,0xc2,0x99,0x3b,0xa0,0x39,0xf1,0x39,0x58,0x7f,0xd2,0x49,0x94,0x3c,0xc3,0xe1,0xb6,0x56,0x38,0x55,0x6f,0xb5,0x1a,0x90,0xa2,0x04,0x2f,0x19,0xf8,0xb1,0x65,0x5a,0xad,0xcd,0x1c,0x56,0x42,0x38,0xc2,0x52,0x09,0xd6,0x41,0x98,0x5d,0x5f,0xa5,0xe7,0xc2,0x55,0xa1,0x09,0x20,0xf2,0xbc,0x6a,0x9b,0x89,0xfb,0xe9,0x85,0x95,0xd6,0x22,0x5e,0x4d,0x6d,0x83,0x9d,0xf4,0xbe,0x66,0x05,0x32,0xb6,0xe2,0xf1,0x96,0x42,0xa4,0xc8,0x8c,0x1b,0xec}},
|
||||
{{0xf2,0x4a,0x96,0x57,0xc3,0x2f,0xe6,0x9f,0xed,0x7f,0xcc,0xe9,0xea,0xbe,0xd2,0x23,0x4e,0x47,0x13,0xd9,0x53,0x19,0x31,0x14,0x0a,0xd3,0x9b,0x95,0xa7,0x9c,0x88,0x5e,0x08,0xb2,0x16,0xda,0x45,0x61,0x1d,0x6b,0xdf,0xb1,0x14,0x0c,0x66,0xfd,0x3a,0xbe,0x25,0xdc,0xfd,0xcd,0xcc,0x5e,0x28,0x77,0x5a,0xa9,0x8b,0x84,0x77,0x26,0x9d,0xa6},{0xea,0xde,0x4d,0xab,0x09,0x02,0xbf,0x90,0xf8,0xae,0x8b,0x50,0x01,0xb2,0x9d,0x7c,0x0a,0x3b,0x60,0xda,0x34,0xa9,0xbb,0x4d,0xa5,0x53,0x18,0x65,0xec,0xaa,0xc9,0x29,0xb2,0xf7,0x74,0x14,0x63,0x5f,0x88,0xcf,0x4e,0x70,0x1b,0x11,0x64,0x73,0x15,0x6b,0x5a,0x8c,0xb8,0x4e,0x0f,0x83,0xae,0x4b,0x5c,0x52,0x1c,0x6a,0x0f,0x54,0x77,0xc8},{0xae,0xff,0x55,0xbf,0x78,0xb5,0xde,0x33,0xeb,0x87,0xea,0x13,0x7d,0x36,0x22,0x06,0x32,0xc4,0x7e,0xca,0x65,0x37,0xcc,0x83,0x0e,0xda,0x54,0xb3,0xd2,0xe6,0xe7,0x7f,0xe1,0x90,0x11,0x25,0x16,0x83,0x25,0x43,0xb4,0x38,0x06,0xbb,0x6c,0x62,0x7d,0x84,0x1f,0xf3,0x7b,0xeb,0xae,0x50,0xd8,0xfb,0xb9,0xf2,0xf9,0xc3,0x6f,0x59,0xb7,0xb0},{0x95,0x15,0x83,0x19,0x56,0x9c,0x11,0xd8,0x31,0x87,0x1d,0xe3,0x3f,0x07,0x89,0xb2,0xcb,0x81,0xf0,0xeb,0x0b,0x1e,0x74,0x08,0xa2,0x4a,0x0e,0x82,0xc6,0x45,0x8c,0x32,0xb4,0x8f,0xfd,0x76,0xeb,0x5e,0xc7,0x62,0xdc,0xcb,0xee,0xad,0xcf,0xcf,0xea,0x33,0x9d,0xb0,0x02,0x64,0x66,0x77,0x14,0x97,0x0c,0x6e,0x79,0xe8,0x58,0x32,0x0f,0xe6},{0xcb,0x2f,0xaf,0x53,0xd8,0x41,0x48,0x41,0x6f,0x36,0x78,0x80,0x83,0x5c,0x0d,0x4c,0x1b,0xf4,0x39,0xe0,0x34,0x4f,0xc2,0xb2,0x4e,0xf0,0xac,0xc2,0xf8,0x15,0x7a,0x81,0x9f,0x46,0x2b,0xe3,0xb9,0x39,0x05,0x89,0xa2,0xda,0x1a,0x63,0x51,0xb4,0x78,0x0f,0xfe,0x2f,0x9d,0xce,0x99,0x38,0xa9,0x7e,0xcb,0x80,0x57,0x9f,0xa2,0x28,0x0f,0x6a},{0x1b,0xec,0x67,0x50,0xd1,0x28,0x65,0x55,0xb8,0xde,0x3b,0x2e,0x1e,0x33,0xd8,0x1b,0xba,0x2e,0x78,0x6a,0xb8,0x0b,0x8c,0xa0,0x55,0x34,0x25,0x90,0x9a,0xe2,0xf5,0xaa,0x95,0x0c,0x6f,0x2a,0xb0,0x92,0x1d,0x48,0x5b,0x56,0x8c,0x82,0x8f,0xa7,0x15,0x75,0x26,0x61,0x85,0xc8,0x7d,0xda,0xf5,0x2a,0xf3,0x3c,0x34,0xc1,0x20,0x67,0xbb,0x04,0xec,0x7c,0xe2,0xcb,0x31,0xcf,0x23,0xda,0x5d,0x8a,0x05,0x00,0x9b,0x23,0x34,0xd0,0xed,0x56,0x10,0x0a,0x90,0x6b,0x73,0x26,0x6b,0xf0,0xd7,0xbc,0xd8,0xc7,0x89,0xc8},{0x90,0x43,0x54,0x87,0x44,0x00,0x07,0xca,0xa8,0x2b,0xec,0x55,0xa0,0xd2,0x8c,0x07,0x03,0xaa,0x61,0x1a,0x7d,0x0f,0x90,0x13,0x67,0x99,0x46,0x20,0xcd,0x70,0xcb,0xa7,0x96,0xdf,0x0c,0x13,0xc4,0x41,0x11,0xd6,0xc3,0x33,0x02,0x96,0x4f,0x1d,0xbd,0x06,0xa9,0xa1,0x31,0x0a,0xc3,0xdf,0x6d,0x52,0x6c,0xc6,0xbe,0xc5,0xb6,0x2a,0xb1,0x0f,0xec,0x7c,0xe2,0xcb,0x31,0xcf,0x23,0xda,0x5d,0x8a,0x05,0x00,0x9b,0x23,0x34,0xd0,0xed,0x56,0x10,0x0a,0x90,0x6b,0x73,0x26,0x6b,0xf0,0xd7,0xbc,0xd8,0xc7,0x89,0xc8}},
|
||||
{{0x4f,0x3a,0xdd,0x0f,0xcf,0x7f,0x27,0xda,0x27,0xc4,0xa6,0x2b,0x6b,0xd1,0x9f,0x59,0x73,0x5f,0xd4,0xb7,0xf0,0x86,0x16,0xc9,0xdd,0xa6,0xf9,0x9b,0x17,0xb2,0xb9,0x71,0xe7,0x4c,0xa1,0x17,0x79,0xe0,0xcc,0xae,0x10,0xec,0x28,0x3a,0x09,0xf2,0x8b,0x34,0x9c,0xac,0x16,0x2a,0xa9,0x21,0xe8,0xa7,0x18,0xc0,0xc4,0x9f,0x30,0xa0,0x25,0x62},{0x23,0x4c,0xd4,0xae,0x52,0x30,0xf6,0x64,0xb9,0xe1,0x47,0xca,0xf8,0xf3,0x3a,0x6b,0x8b,0xf3,0x29,0xe2,0x9b,0x5d,0xbb,0x0a,0x60,0x52,0x03,0x40,0x53,0x5c,0x9e,0x35,0x03,0xd4,0xec,0xd7,0x67,0xf4,0x92,0xd2,0x98,0x96,0xf2,0xa7,0xf4,0x25,0x6a,0x80,0x9c,0x75,0xc6,0xf2,0x1f,0x67,0x11,0x00,0x0d,0xda,0x1e,0xb2,0x58,0xa7,0x8c,0x39},{0x55,0x1b,0x80,0xbb,0xf3,0xc5,0x1a,0x84,0x34,0xf5,0x0a,0x8a,0x8a,0xe1,0x8c,0xea,0xa6,0xfb,0xd0,0x26,0xc9,0xa2,0x30,0x37,0x3e,0xba,0x98,0xfe,0x81,0x8a,0x52,0x37,0x0b,0x74,0x4e,0x3d,0x26,0x8f,0x82,0x4b,0xc0,0x6a,0x01,0x10,0x91,0x8f,0x89,0xb5,0x62,0x3f,0x1e,0x70,0xcc,0x25,0x77,0x39,0x74,0x88,0xdd,0xbc,0xbe,0x72,0x08,0x63},{0xe2,0x9a,0x46,0xd2,0x74,0xdc,0x0f,0x8a,0xa3,0xbd,0x20,0xb7,0xc7,0xd9,0x83,0x4b,0x58,0xa6,0xe3,0xbd,0xc5,0x00,0xb6,0x18,0x04,0x25,0x81,0xbd,0x99,0xb3,0xb1,0x2a,0x7a,0x68,0x6d,0xe1,0x3e,0x23,0x8d,0x29,0x9e,0x7a,0x30,0x56,0x4c,0x22,0xb6,0xf4,0x7d,0x7d,0x4f,0xfd,0x76,0xa5,0x9d,0x05,0x41,0x7c,0x7a,0x2d,0x7b,0xbe,0xcf,0x73},{0x7b,0xae,0x11,0x86,0x8a,0x38,0xbd,0x56,0x3c,0xf3,0x3c,0x9c,0x49,0xa4,0x68,0x0f,0x2b,0xdf,0xf2,0xa1,0xbc,0xc2,0xed,0x08,0x09,0x96,0xd0,0x7e,0x9b,0xe3,0x0a,0x72,0x13,0x03,0xd4,0x35,0x0a,0x94,0x60,0x09,0x4a,0xaa,0xca,0x35,0x8e,0xed,0x12,0xdd,0x26,0x8f,0xf8,0xa9,0xa2,0x8a,0x7f,0xac,0xf3,0x09,0xc7,0x22,0xc5,0x73,0xec,0xa0},{0xe9,0xc5,0x57,0x0d,0x85,0xbf,0x10,0xe2,0xd1,0xf5,0xd7,0x22,0xe9,0x6a,0x67,0x8d,0xd3,0x9f,0x1a,0xef,0x7f,0xc0,0x2b,0xe1,0xfd,0x2c,0xc2,0x5f,0x39,0xf9,0x34,0xd0,0x87,0x94,0x41,0x8a,0x65,0xa5,0x20,0x48,0xa4,0x20,0x5f,0x7a,0xc7,0x37,0x00,0x60,0x59,0x84,0x2a,0x1d,0xff,0x02,0xc3,0xe8,0x20,0xaa,0x39,0x13,0xac,0xf3,0xd7,0x05,0xbd,0xef,0x11,0x66,0x71,0xb8,0x9f,0x1e,0xe5,0xee,0x2e,0x37,0xfb,0x34,0xed,0xc5,0xa4,0x40,0x6e,0x38,0x31,0x0a,0x1c,0xaf,0x0d,0xd3,0x98,0xac,0x12,0x40,0xea,0x9c},{0xc6,0xcd,0x7a,0xbd,0x14,0xdb,0xe4,0xed,0xbf,0x46,0x70,0x23,0xbd,0xdb,0xc3,0xce,0x60,0xd5,0x6b,0x17,0x4c,0x23,0xfa,0x78,0x05,0xcc,0x18,0xed,0x42,0x03,0xa5,0xb7,0xdf,0x28,0x0e,0xd4,0x5d,0x31,0xd8,0xb9,0xdc,0xe9,0xf6,0x26,0xc5,0xe1,0xb3,0x80,0x0d,0x62,0xaf,0x2d,0xbd,0xd6,0xe4,0xbb,0x16,0x82,0xc8,0x13,0x2a,0x6f,0xb9,0x06,0xbd,0xef,0x11,0x66,0x71,0xb8,0x9f,0x1e,0xe5,0xee,0x2e,0x37,0xfb,0x34,0xed,0xc5,0xa4,0x40,0x6e,0x38,0x31,0x0a,0x1c,0xaf,0x0d,0xd3,0x98,0xac,0x12,0x40,0xea,0x9c}},
|
||||
{{0x6f,0x46,0xcd,0x96,0xc4,0x13,0xf4,0x11,0x62,0x49,0x8c,0x5c,0x78,0x27,0xef,0xc8,0xb9,0xe2,0x7d,0xf1,0x0d,0x37,0xf2,0xfe,0x85,0x35,0x82,0x60,0x23,0xb6,0x7b,0x17,0xd2,0x91,0xef,0x01,0x9e,0x99,0x35,0xab,0xc7,0xfb,0xa1,0xa3,0x13,0x44,0x3f,0x3c,0x16,0xcb,0xd8,0xf0,0xbf,0x9e,0x65,0x4d,0x07,0xe0,0xfd,0x8e,0x32,0x61,0x95,0xd5},{0xb7,0x81,0x16,0x2f,0xcb,0xa4,0x30,0x4e,0x6d,0xf5,0xf0,0x3f,0xfe,0xd9,0x81,0x20,0xa6,0x0e,0x2b,0xa8,0xc5,0xed,0x0d,0x9a,0x28,0x9c,0xe3,0xa9,0xb7,0xbf,0x87,0x0f,0xa5,0xf9,0x33,0xe7,0xa6,0x7f,0x9b,0xac,0xb6,0xcc,0xaf,0xfc,0xa7,0x4a,0x4d,0x36,0x39,0xa9,0xb6,0xf5,0x09,0xde,0x8d,0x37,0x11,0x07,0xd1,0x8a,0xf5,0x7b,0x66,0xe1},{0xcc,0xe0,0x07,0x62,0xbe,0x10,0x8c,0x3a,0xa2,0x96,0x5d,0x11,0xc7,0xd5,0x50,0xc3,0xbb,0x55,0x21,0xc5,0x40,0x27,0x7d,0xdb,0xad,0xd2,0x61,0x2a,0x42,0x5f,0x94,0x23,0x77,0x83,0x3a,0x99,0xe8,0xda,0x79,0x8c,0x1e,0xa8,0x44,0x04,0xec,0xf5,0xd1,0x55,0x1e,0x58,0xf1,0x6e,0x4d,0x27,0xa4,0x91,0xec,0x59,0xc8,0x17,0x36,0x58,0x2a,0x1f},{0x6d,0xf8,0x73,0xa3,0x38,0x61,0x1d,0x95,0x09,0xde,0xe5,0x26,0x1b,0x15,0x16,0xfb,0xf5,0x16,0xa8,0xf3,0x9e,0x3a,0x6b,0xb5,0x8c,0xee,0xa8,0x66,0x79,0xc3,0x9e,0xb4,0xe1,0xc2,0x85,0x0e,0x86,0x10,0x5a,0x4e,0x8b,0x4c,0x0a,0x7a,0xd8,0x8a,0x48,0xf4,0xa0,0x79,0x37,0xe3,0xa5,0x90,0x05,0x5e,0xbd,0xa1,0xf6,0x09,0x58,0x9c,0x6f,0x09},{0x66,0x47,0x6d,0x60,0x06,0x2d,0x90,0x8f,0xae,0x6c,0x01,0xe9,0xb0,0xf9,0x6b,0xa5,0x4a,0xe1,0xdb,0xd3,0x64,0x42,0x37,0x5c,0x11,0x40,0x7a,0xce,0x4e,0x83,0xc3,0x2c,0x2e,0xd2,0x67,0x76,0xfb,0x8c,0x5d,0xab,0xe8,0xb8,0xd6,0x2b,0xf8,0x86,0xff,0x96,0xf3,0xa8,0x0e,0x2b,0x1a,0x68,0xf5,0xe4,0xee,0x49,0xa6,0x8c,0x41,0x1f,0x97,0xbf},{0x81,0x92,0x4e,0xc6,0xab,0x00,0xdd,0xf9,0xf9,0xb7,0xe0,0x0a,0xa9,0x3f,0x0a,0xf9,0x32,0x73,0xf6,0x22,0xec,0x95,0xd9,0x20,0x8a,0x3f,0xeb,0x0d,0xc7,0x79,0x6f,0xb3,0x85,0xf4,0xe1,0x11,0xe1,0xcc,0xaa,0x1b,0xfd,0xf3,0x43,0xff,0x66,0x73,0x0f,0x09,0xcc,0xa4,0x6c,0xb8,0x2a,0x0f,0x53,0x58,0x63,0x32,0x06,0xd9,0x6b,0x1a,0x14,0x04,0x85,0x3f,0x2f,0x2b,0x05,0xfb,0xed,0xe9,0x08,0x0d,0x21,0x49,0xc9,0x79,0xdf,0x6f,0x77,0x89,0xd7,0x74,0x09,0x57,0x1a,0xd2,0xa7,0x43,0xbf,0x08,0x8e,0x98,0xbc,0x2f},{0xe3,0xb1,0xc4,0x81,0xe6,0xec,0x07,0x58,0xa4,0xcb,0x7e,0xd5,0xae,0x9d,0x43,0xf1,0xb7,0xe2,0x0a,0x1f,0xd5,0xe8,0x14,0xba,0x22,0xff,0xb7,0x20,0x76,0x08,0xdc,0x9a,0x44,0x4c,0x1c,0xcd,0x38,0x4d,0xb5,0xd8,0xa9,0x1b,0x9d,0xbb,0x13,0x5a,0x6c,0xe9,0x5d,0xa4,0x42,0x0e,0xde,0x9a,0x47,0x8a,0x2a,0x97,0x42,0x86,0x87,0x98,0x3f,0x04,0x85,0x3f,0x2f,0x2b,0x05,0xfb,0xed,0xe9,0x08,0x0d,0x21,0x49,0xc9,0x79,0xdf,0x6f,0x77,0x89,0xd7,0x74,0x09,0x57,0x1a,0xd2,0xa7,0x43,0xbf,0x08,0x8e,0x98,0xbc,0x2f}},
|
||||
{{0xff,0xe3,0x69,0x7b,0x62,0x45,0x40,0x5f,0x1c,0x49,0x65,0xd6,0xae,0x24,0x16,0x84,0xfa,0x69,0x6c,0x1f,0x6c,0x65,0xee,0x52,0xe9,0x6c,0x54,0xc7,0x31,0x9b,0xc2,0x74,0x4f,0xc0,0x16,0xb8,0xf8,0x75,0x5f,0x45,0xb5,0xf3,0xa0,0xd9,0xbe,0x25,0x82,0xbd,0x3c,0x03,0xe0,0x14,0x15,0x6a,0xd5,0x64,0x08,0x65,0x13,0x33,0xc2,0xab,0xe0,0x45},{0x6f,0x5a,0x90,0x80,0x25,0x13,0xc2,0xa7,0xfe,0x1c,0xa1,0x07,0x81,0x4b,0x09,0xd3,0xbd,0xda,0x55,0xa8,0xaa,0x62,0x19,0x03,0xe9,0x9f,0x77,0xef,0xff,0xd4,0x5e,0x53,0xbc,0x9d,0x71,0xb8,0xc4,0xc2,0x85,0xb9,0xb4,0x3d,0x95,0xb8,0xfd,0x44,0xb7,0xc8,0x6f,0x93,0x15,0x04,0x16,0x7e,0x01,0xf2,0x09,0x23,0x96,0x69,0xe5,0x65,0x52,0x34},{0xaf,0xfe,0x4f,0x34,0x4e,0xfe,0x51,0xa5,0xb2,0xd8,0x31,0x74,0x7b,0xae,0xfb,0xb9,0x33,0xc1,0xdc,0x66,0xe6,0x95,0x9e,0xce,0x77,0x7d,0x55,0x3c,0xa6,0x6c,0x09,0x23,0x5a,0x1a,0x5e,0x1a,0x41,0xd3,0xad,0x5f,0x86,0xd0,0x14,0xf5,0xe0,0xda,0xf1,0xce,0x19,0x90,0x45,0x0c,0x4c,0xb1,0xd3,0xc8,0x4c,0xdb,0x7e,0x49,0xf5,0xac,0xde,0xff},{0x1b,0x9b,0x6b,0x30,0xd3,0x19,0x37,0x83,0xad,0x05,0xca,0xba,0x22,0x85,0x33,0x7f,0x55,0x60,0xe3,0x14,0x8c,0x39,0x87,0xd1,0x4c,0x21,0x27,0xa0,0xae,0x4a,0x56,0x15,0x50,0x6c,0x99,0xca,0xff,0xde,0x10,0xc6,0x9f,0x6c,0x70,0xd1,0x66,0xb4,0x87,0xd8,0xfc,0x46,0xf2,0xcf,0x0c,0xd8,0xc3,0x14,0x5d,0x27,0xbd,0xed,0x32,0x36,0x7c,0xed},{0x64,0x6b,0x74,0xc7,0x60,0x36,0xc5,0xe4,0xb6,0xde,0x02,0x1a,0x09,0xaf,0x65,0xb1,0x94,0xa3,0xf4,0x95,0xf5,0xb0,0xef,0x86,0xb5,0x13,0x26,0x0b,0xe8,0xc5,0x5c,0x77,0xf5,0xe6,0xb6,0x10,0x36,0x87,0xa3,0xd2,0x7c,0x17,0x2c,0xb9,0xb0,0x90,0x9e,0x8c,0x0a,0x7d,0x73,0xb2,0x29,0xeb,0xa7,0x85,0xd7,0x04,0x14,0xf9,0x77,0xb7,0xf4,0x89},{0x7f,0x1c,0x5a,0x57,0x14,0xf6,0x30,0x07,0xf9,0xfe,0x42,0x98,0xcb,0x3d,0xac,0x04,0x30,0x0d,0xc6,0xd0,0x4f,0x8a,0xbc,0xdd,0x3e,0xc3,0xb7,0x74,0xc8,0x3b,0x1a,0xcc,0x6a,0x54,0x9e,0xb9,0xbe,0xf0,0x7c,0x35,0x35,0x1a,0x50,0x4c,0xc2,0x38,0x41,0x46,0xc8,0xc4,0x81,0x2b,0x26,0x56,0x6f,0x8a,0x9f,0x74,0x87,0xe0,0x01,0x82,0xe2,0x09,0xf3,0x9a,0xc5,0x33,0x5a,0x7d,0xb6,0xbb,0xff,0x20,0x4d,0xc1,0x99,0x3d,0xcc,0x5a,0xc7,0xd1,0xbe,0x4c,0xcf,0xc8,0x09,0x79,0x15,0x5e,0x0c,0xc6,0x26,0x36,0xe6,0xd9},{0x4d,0x2f,0x08,0x84,0x32,0xcf,0xe0,0x3b,0xa8,0x3e,0xa5,0xf8,0x3a,0xe8,0xa9,0x04,0x5a,0x74,0x67,0xcb,0x41,0x22,0xc5,0xc4,0x9a,0xa5,0xc1,0xa7,0x94,0x8b,0xa5,0x35,0x00,0x00,0x1a,0xaf,0xfb,0xed,0x40,0xb8,0x2b,0x28,0xf1,0xb1,0x02,0xd3,0x8b,0xc0,0x32,0x4a,0xa5,0x0a,0xa4,0xc3,0xbf,0xb3,0xf5,0xb7,0x65,0x8e,0x88,0xdf,0xd0,0x0e,0xf3,0x9a,0xc5,0x33,0x5a,0x7d,0xb6,0xbb,0xff,0x20,0x4d,0xc1,0x99,0x3d,0xcc,0x5a,0xc7,0xd1,0xbe,0x4c,0xcf,0xc8,0x09,0x79,0x15,0x5e,0x0c,0xc6,0x26,0x36,0xe6,0xd9}},
|
||||
{{0xc8,0x8e,0x1c,0xea,0x02,0x6a,0xfd,0x88,0x8b,0xa9,0x9d,0xdd,0xba,0xea,0x77,0x30,0x88,0x1a,0x93,0x49,0xda,0x05,0x18,0xbb,0x4a,0x6a,0x11,0xc4,0x48,0x72,0x77,0x1f,0x6e,0x2b,0x9a,0xe3,0x27,0xbe,0xe1,0x75,0x32,0x30,0xa6,0x12,0x26,0x44,0xbf,0xb2,0xa5,0x51,0x0b,0x48,0x3a,0xea,0xc5,0xd4,0x24,0x3f,0x4e,0xe8,0xe5,0xc3,0xfb,0xc2},{0xcb,0x56,0x3c,0x00,0x28,0x15,0x72,0x16,0x23,0x4e,0x2e,0x2c,0x8c,0xe8,0x7c,0x44,0x82,0x2a,0xe0,0x57,0xa3,0x0a,0xc4,0x42,0xb5,0x07,0xe1,0x1b,0x78,0x8b,0x3d,0x4d,0xcb,0xe4,0x56,0x72,0x0b,0x85,0x52,0xd8,0x55,0xe2,0xcd,0x38,0xd2,0x83,0xb6,0x05,0xd2,0x9f,0x63,0x9e,0x7f,0xca,0xe5,0x95,0x36,0x61,0x9b,0xca,0x09,0x27,0x53,0x82},{0x24,0x67,0x10,0xd6,0x8a,0x1a,0x8e,0xb8,0x53,0xef,0xb7,0x67,0x2a,0xfd,0xb8,0xd6,0xe3,0xf7,0x41,0x95,0x8c,0x50,0xca,0x1d,0x21,0x21,0x41,0xd1,0xef,0x2d,0x9b,0x53,0xa9,0x42,0xcd,0xda,0x6d,0x12,0x1b,0xbd,0x0a,0xe1,0x4d,0x95,0xc6,0xaa,0x40,0xfd,0x98,0xfb,0x26,0x21,0x5e,0xaf,0x8e,0x6b,0xc9,0x36,0x2c,0x66,0x31,0x24,0x45,0x87},{0x5e,0xf9,0x1d,0x10,0xb5,0x79,0x1f,0x80,0x85,0x90,0xc3,0x7f,0x2b,0x73,0xbf,0x83,0x0b,0x5d,0x46,0xae,0x79,0xef,0x09,0x71,0x29,0xfb,0x83,0xde,0x1f,0xe2,0xdb,0x1b,0xa2,0x22,0xee,0x50,0x21,0x9d,0x9c,0x35,0x14,0x48,0x13,0xa5,0xd1,0x68,0xf4,0x61,0x1f,0xd7,0xe2,0xd6,0x42,0x1c,0xdc,0x58,0xec,0x8b,0x03,0x6b,0xdf,0x64,0x06,0x30},{0xf9,0xa6,0x88,0x74,0x07,0x19,0x15,0x38,0xaf,0xac,0x07,0x10,0xe0,0xd9,0x22,0xf3,0x78,0xb0,0xbf,0x60,0xa3,0x0f,0xea,0x0f,0xa8,0x64,0xa9,0xa3,0x82,0xe1,0x4c,0x29,0x36,0x22,0x6d,0x43,0x9c,0xde,0x22,0xbf,0xc6,0x85,0xf7,0xe9,0xe0,0x79,0x80,0xfe,0x9d,0xd6,0x24,0xbd,0x29,0xa4,0x8c,0x35,0x21,0x87,0x45,0x7f,0x88,0xd9,0x9a,0x9d},{0x49,0x43,0x19,0x14,0xcc,0x4a,0x11,0x01,0x05,0xd1,0x4e,0x39,0x6d,0xb0,0x22,0x65,0x32,0x6e,0x67,0x04,0x50,0x85,0x53,0x42,0x90,0x2c,0xc0,0x63,0x2f,0xbd,0x15,0x90,0x1b,0x3f,0x03,0x90,0x16,0x7f,0x7b,0x49,0x74,0xd0,0x3d,0x81,0x80,0x1e,0x9e,0x2e,0xa9,0x13,0x6a,0x10,0x14,0xc1,0xfd,0xf9,0x25,0x3a,0x1d,0x52,0x93,0x0a,0x77,0x03,0xa2,0xdd,0xce,0x9f,0x2a,0x35,0xc9,0x93,0x7c,0xa2,0x2c,0xf6,0x38,0x73,0xb3,0xab,0x7f,0x55,0xb6,0x62,0xa2,0x8d,0x6a,0x3e,0x88,0x04,0x9b,0xa2,0x19,0x64,0x55,0x01},{0x22,0x03,0x49,0x58,0x76,0x3c,0x85,0x45,0x5e,0x73,0x78,0x8f,0x65,0xc9,0x50,0xf8,0xd7,0x16,0x92,0xa4,0xd1,0x79,0xce,0xf3,0x00,0x34,0x38,0xb8,0xcc,0x96,0x9f,0xa6,0x87,0x28,0xcb,0x19,0x28,0xad,0x83,0xb5,0x09,0x96,0x54,0xe8,0x2a,0xb9,0x9b,0xff,0x60,0x85,0x31,0x28,0x62,0x36,0xd2,0x0e,0xad,0x2a,0xe1,0x84,0x80,0xeb,0x6f,0x00,0xa2,0xdd,0xce,0x9f,0x2a,0x35,0xc9,0x93,0x7c,0xa2,0x2c,0xf6,0x38,0x73,0xb3,0xab,0x7f,0x55,0xb6,0x62,0xa2,0x8d,0x6a,0x3e,0x88,0x04,0x9b,0xa2,0x19,0x64,0x55,0x01}},
|
||||
{{0xeb,0x18,0x95,0x94,0x5f,0x15,0x8c,0xb8,0x4d,0x6e,0x7d,0xc0,0x96,0x6c,0x52,0xa2,0x5f,0x43,0x67,0xc2,0x3a,0x10,0x5b,0xf1,0x8f,0x21,0x89,0x06,0x77,0xe9,0xab,0x2e,0xcd,0x17,0x9c,0x9a,0xd7,0x89,0x7e,0x53,0x58,0x60,0x9b,0xce,0x90,0xd9,0x13,0x2d,0x78,0xc4,0x2c,0x1c,0x4c,0xe8,0x23,0x70,0xff,0xa0,0x42,0x98,0x25,0x40,0xd6,0xd8},{0xb6,0xfb,0xdd,0x5d,0x35,0xf2,0x2b,0x89,0xda,0x8e,0x90,0xee,0x03,0x4e,0x75,0xdb,0x4c,0x45,0xc8,0x00,0xde,0x06,0x27,0xde,0x44,0xb5,0x5b,0xc7,0x56,0xc3,0xf5,0xbb,0xee,0xa6,0x21,0xd4,0xd9,0xb9,0x24,0x9c,0x4c,0xbc,0x23,0xe5,0xeb,0x05,0xb6,0xd0,0xd0,0xbf,0x49,0x95,0x01,0xb4,0x97,0xad,0xb5,0x71,0x8d,0x4b,0x32,0xd0,0xdd,0x1a},{0xfd,0x11,0xd7,0xe4,0x46,0xcd,0xd8,0x44,0x89,0x0a,0xe7,0x44,0x59,0xe9,0xcf,0x9f,0xd6,0xf1,0x74,0x56,0x04,0x78,0xfa,0x29,0x46,0x8a,0x8d,0x1b,0xbe,0x41,0x92,0x1c,0x8d,0x74,0x01,0x1b,0xc1,0xf8,0x26,0xf4,0xc2,0x68,0xc3,0x23,0x8c,0x68,0x7c,0x0a,0xad,0xdd,0x50,0x10,0xcf,0xdb,0x78,0xc5,0x79,0x28,0x37,0x63,0x92,0x1a,0x1d,0xea},{0xd2,0x2a,0xf0,0x66,0x15,0x8b,0xcb,0x83,0xcf,0x34,0xa1,0x33,0x6b,0xd5,0xa8,0x98,0x3b,0xd7,0x09,0x0d,0x70,0xa5,0x8a,0xc0,0x73,0xcf,0xde,0x59,0xd5,0x13,0x41,0xd2,0x43,0x8b,0xb4,0xc3,0x5b,0x6f,0xf1,0xed,0x47,0x76,0xe6,0x5e,0xb8,0x2a,0x7e,0x20,0x91,0xa0,0x9d,0xc1,0xa2,0x0a,0x6d,0x97,0x7d,0xeb,0xe3,0x64,0x5f,0x86,0xff,0x3e},{0x45,0xd8,0xdc,0xe4,0x3a,0x3a,0x44,0xdc,0x7f,0xa8,0x92,0x11,0x1b,0x4f,0xfa,0xcf,0x21,0xff,0xfb,0x20,0xb0,0x02,0x6d,0x0e,0x1c,0xde,0xe8,0x51,0xd8,0x2c,0x72,0x0e,0xbf,0xf6,0x9a,0xd3,0xd3,0xfe,0xfa,0x98,0x4e,0xc2,0xf0,0x16,0xda,0x39,0x93,0xc4,0xe0,0x33,0x9a,0x43,0xe8,0x7a,0xc5,0x0f,0x0b,0xa4,0x45,0xf0,0x5e,0x7a,0xa9,0x42},{0xdb,0x4e,0x17,0x76,0x8b,0x3c,0x98,0x7f,0x58,0x76,0x97,0xc9,0x3f,0x99,0x01,0x05,0x42,0x7e,0xfd,0x83,0x99,0xaa,0x19,0xb5,0x72,0x4c,0x69,0xed,0x6e,0x21,0x79,0x6e,0x3b,0x71,0xe5,0xab,0x23,0x84,0xe7,0xfe,0x58,0x2b,0x0d,0x1e,0x75,0x7c,0x29,0xb3,0x2d,0x66,0xc2,0x45,0x88,0xac,0x86,0x29,0xe4,0xaa,0x9e,0x71,0xa1,0x88,0xf9,0x06,0xda,0xa3,0xdd,0x7b,0x6c,0xd9,0xc9,0x73,0xe9,0x56,0xd1,0xee,0x5b,0xf9,0xae,0xc0,0x29,0xbe,0x20,0x6c,0xc7,0xf9,0xc5,0x2d,0x6d,0xad,0x8f,0x49,0xf8,0x17,0xdb,0x7a},{0xb8,0xb7,0xec,0xeb,0x3e,0x40,0x77,0x6c,0xab,0x10,0xfe,0x9f,0xd1,0x40,0xfe,0xd2,0x88,0x8e,0xb0,0x55,0xae,0x75,0xb1,0xcc,0x9d,0x6c,0x11,0x28,0x95,0x38,0x9f,0xb9,0x59,0xe2,0x29,0xc3,0xbc,0x09,0x16,0x1f,0x17,0x9e,0x15,0x78,0x09,0x61,0x07,0x9e,0xad,0x67,0x98,0xa9,0x24,0xff,0xf9,0x4b,0xa2,0x76,0x09,0xa0,0xd7,0x1b,0xed,0x05,0xda,0xa3,0xdd,0x7b,0x6c,0xd9,0xc9,0x73,0xe9,0x56,0xd1,0xee,0x5b,0xf9,0xae,0xc0,0x29,0xbe,0x20,0x6c,0xc7,0xf9,0xc5,0x2d,0x6d,0xad,0x8f,0x49,0xf8,0x17,0xdb,0x7a}},
|
||||
{{0xc3,0x92,0x4d,0x01,0x9c,0xea,0x5a,0x8d,0xbd,0x5c,0x12,0x58,0x6d,0x03,0x26,0xbf,0xa4,0xdd,0xf7,0x26,0xa4,0x0d,0x22,0xe0,0xbd,0xcc,0x6f,0x30,0x9e,0xf9,0x4c,0x1f,0x03,0x52,0xab,0x38,0xe9,0x9c,0x08,0x9c,0x09,0xe5,0x87,0x5c,0x24,0x1a,0xe2,0x75,0xcb,0x18,0x8a,0x63,0x50,0xd1,0x23,0x45,0x49,0x93,0x40,0x2c,0x09,0xd4,0xac,0x39},{0xd4,0xe7,0xb7,0x05,0xfd,0xd6,0xf3,0x57,0xfb,0xc2,0x2f,0x2c,0x71,0x80,0xf5,0xc3,0xa6,0x0a,0x23,0x9d,0x1d,0xa8,0x68,0x10,0x8a,0xfa,0x68,0x9d,0x2b,0xcf,0x96,0xa9,0xe6,0x0e,0x07,0x32,0x23,0x09,0x87,0x16,0xc5,0xbb,0x76,0x22,0xfc,0xb4,0x59,0x6d,0x67,0xfd,0x29,0x51,0x95,0x4c,0xe2,0x8c,0x18,0xab,0xda,0x84,0xc3,0x62,0x80,0x14},{0xc9,0xa1,0xfe,0xc3,0x48,0x0d,0xee,0x54,0x44,0xff,0x9c,0x46,0x04,0x0e,0x74,0xda,0xa4,0x6a,0x56,0x02,0x5f,0x76,0x0e,0xb5,0xc1,0xc9,0xe9,0xb2,0x6e,0x07,0x49,0x0c,0xf7,0x4b,0xee,0xd6,0x0a,0xad,0x94,0x03,0x58,0x2d,0x60,0x95,0xf8,0x16,0x7b,0x49,0x0b,0x01,0x66,0x3e,0x17,0x01,0xe5,0x54,0x7d,0xd7,0xbb,0x10,0xd1,0xad,0xad,0x79},{0xb2,0xd8,0x10,0x29,0xeb,0xb8,0x4e,0x2b,0x39,0x85,0x5c,0xb3,0xdc,0xf5,0x87,0xca,0xca,0x9c,0x7a,0x8c,0x2b,0x08,0xe8,0x25,0xe2,0xcf,0x70,0xe2,0xe6,0xfb,0xdb,0x0c,0xc3,0x0d,0x71,0x11,0x83,0x65,0xf2,0x71,0x08,0x1b,0x32,0x6e,0x6c,0x51,0x50,0xf1,0xf6,0x4b,0x54,0x63,0x16,0x7f,0xfd,0x80,0x05,0x61,0x63,0xf1,0x80,0x6a,0x0b,0xfd},{0xa7,0x4b,0x75,0x38,0x90,0x64,0x96,0x7b,0xda,0x5e,0x08,0x9b,0x80,0xc4,0x72,0x3f,0x73,0xb2,0xdb,0xd3,0x4a,0xed,0xa4,0xdc,0x5c,0x79,0xe5,0x0f,0x7a,0xd3,0x0c,0xac,0xf9,0x99,0x5c,0x1a,0x0f,0xb3,0x1a,0x0f,0x5c,0xc3,0x9e,0x1a,0x2b,0xfa,0xc3,0xf0,0x40,0xe5,0x5f,0x36,0xd2,0x98,0x31,0xa1,0xaf,0x18,0x5f,0xae,0x92,0xf3,0x9e,0xc0},{0xf9,0xbf,0x52,0xe6,0xd3,0xe1,0x5d,0xd3,0x30,0xf3,0xa1,0x0c,0xc8,0x5a,0x97,0x55,0xab,0x67,0x67,0xd0,0x00,0x62,0x7b,0x80,0x70,0xbf,0x24,0xd0,0x09,0x8b,0x07,0x77,0xeb,0x3e,0xf0,0x5d,0xdf,0x7b,0xa9,0x7d,0xa4,0x6a,0x0d,0xf1,0xac,0x83,0x7d,0x64,0xb5,0xf4,0xc6,0xc4,0x12,0x0c,0x55,0x9f,0x67,0xbb,0xd5,0xe3,0xd3,0xdb,0x17,0x0f,0x90,0x2f,0x8f,0xc9,0xfd,0x4e,0x6c,0x8b,0xe6,0x99,0xfa,0xda,0x8f,0x1f,0xe6,0xc3,0xeb,0xd8,0x14,0x20,0xcc,0x3c,0x1c,0x23,0x77,0x28,0x9b,0x22,0x9a,0x5a,0x0c,0x43},{0xa2,0x78,0x37,0xc9,0x63,0xe1,0x31,0x36,0xc2,0x58,0xac,0xca,0xbb,0xa2,0x84,0xaa,0xb3,0x82,0xe2,0x19,0xb7,0x14,0x96,0x27,0x77,0xfa,0xa1,0x02,0xaa,0xff,0x55,0x82,0xba,0xc0,0x38,0x1a,0x69,0x35,0x48,0x87,0xc2,0xeb,0x48,0x08,0xea,0xc5,0x6b,0xfc,0x84,0x60,0x4e,0xce,0xd7,0xd2,0x86,0x8b,0x76,0xf3,0x46,0xe1,0x87,0x1f,0xff,0x09,0x90,0x2f,0x8f,0xc9,0xfd,0x4e,0x6c,0x8b,0xe6,0x99,0xfa,0xda,0x8f,0x1f,0xe6,0xc3,0xeb,0xd8,0x14,0x20,0xcc,0x3c,0x1c,0x23,0x77,0x28,0x9b,0x22,0x9a,0x5a,0x0c,0x43}},
|
||||
{{0x0e,0xa6,0x0c,0xef,0x12,0xd6,0x7d,0x71,0xd4,0x88,0x73,0x86,0x9a,0x88,0x8f,0x5b,0xd1,0xb6,0x12,0xc4,0x93,0x8b,0x5f,0xee,0xdd,0x9c,0x2a,0x7f,0x4d,0xfd,0xba,0x00,0x09,0x45,0x77,0xd2,0xcf,0xcd,0x3a,0x6f,0x27,0x44,0xe2,0x55,0x3e,0x79,0x88,0x4d,0x5f,0x38,0x34,0xe8,0xe7,0xc6,0x3a,0xde,0xef,0x99,0x15,0xea,0x88,0x79,0xd7,0xca},{0xa0,0x9a,0x0a,0x3a,0x42,0x35,0x54,0x78,0xb9,0x82,0x52,0xb4,0xc8,0x5c,0x4a,0x03,0xa1,0xb9,0x27,0xcc,0x99,0xec,0x03,0xdf,0xdd,0x6e,0xde,0xef,0x8f,0x7f,0xdc,0x5a,0xc3,0xcb,0x0e,0xa2,0x7e,0x93,0xe6,0xdd,0xbd,0xf1,0x1b,0x03,0x29,0x63,0x72,0x11,0x72,0x3d,0x24,0x6f,0xdf,0x8e,0xed,0xa4,0xe2,0x2a,0x4c,0x00,0xe2,0xc4,0x55,0x1b},{0xb2,0xf1,0xff,0xf6,0x3a,0x26,0xe1,0x74,0x52,0xba,0xee,0x28,0xb6,0x56,0x90,0x59,0xde,0x92,0x5f,0x84,0xd1,0x87,0xe2,0x64,0xce,0xdc,0x94,0x3c,0xb4,0xf8,0x01,0x0a,0x86,0x2f,0xfe,0x79,0x03,0x72,0xfc,0x26,0x21,0xc3,0x1e,0xec,0x63,0x29,0x64,0xcb,0x5f,0xcc,0xb6,0x78,0xf7,0xc8,0xd1,0xf8,0x5c,0xc4,0x4b,0xc0,0xc3,0x75,0x3e,0x46},{0x03,0x4b,0xb9,0xd1,0x50,0xa3,0x79,0xbe,0x74,0xa3,0xb5,0xd8,0x28,0x1b,0x6d,0x72,0x68,0x0a,0x9b,0x19,0xc9,0x13,0xc4,0x04,0x94,0x0a,0xcb,0x72,0xff,0x7d,0xb6,0x9a,0x1c,0xfd,0xe4,0xa3,0x75,0x13,0x57,0x36,0xfe,0x4a,0xf6,0xbc,0xca,0xd9,0x34,0x9b,0xef,0x90,0x02,0xd9,0xbd,0xdd,0x6f,0x22,0x54,0x36,0xb2,0x3f,0x22,0x65,0xef,0xe7},{0x04,0xd4,0x43,0xe8,0x8c,0xc4,0xfb,0xe5,0x55,0xd0,0xa4,0xea,0x20,0xf8,0xe1,0x8f,0xc2,0xbc,0x1f,0x55,0xf1,0x8d,0xda,0xc0,0x85,0xa4,0xef,0x36,0x97,0x22,0x8b,0x8e,0x77,0x4c,0x1a,0xa4,0xa0,0x6f,0xe1,0xdc,0x32,0x47,0xc4,0x3a,0xd8,0x8a,0xbd,0x19,0x30,0x1c,0x96,0x7a,0xb2,0x23,0x7c,0x16,0x03,0xa7,0x4f,0xfd,0xa6,0x50,0xd9,0xf7},{0xdf,0xc2,0x59,0xd2,0xa9,0x9b,0x1e,0xca,0xf0,0x39,0x2f,0xf8,0xc2,0xf3,0x91,0x55,0x1b,0xba,0x81,0x3a,0x67,0x1a,0xd4,0xf4,0xb0,0x9f,0xb6,0x18,0x38,0x65,0x3e,0x67,0xa0,0x37,0xc2,0x9a,0xc7,0xee,0x72,0x8e,0x13,0x64,0xd1,0x0a,0xda,0xbd,0x8d,0xa4,0x28,0x55,0x3a,0x2c,0x78,0x41,0xc6,0xfc,0x1c,0x0f,0xf8,0xd7,0x5f,0xe6,0xde,0x0b,0xd5,0xc0,0xaa,0x2c,0x5c,0xac,0x46,0xeb,0xa4,0x35,0x2a,0xab,0x00,0x2e,0xc0,0x8b,0x42,0x65,0x2f,0x2f,0x13,0x84,0x60,0x15,0xa3,0x69,0xee,0xab,0x0e,0x50,0xbf,0x5f},{0xc1,0xb0,0xac,0x4c,0xfa,0x62,0x52,0x22,0xae,0x8c,0x94,0x38,0xd9,0x6e,0x10,0x94,0xe7,0xaa,0xc0,0x92,0x93,0x06,0x55,0xf9,0x2e,0xd9,0x10,0x4d,0xcb,0x82,0x19,0x1f,0x27,0x16,0x81,0xdd,0xea,0x7a,0xa8,0xce,0x5a,0xdd,0x37,0x77,0x24,0x57,0xfb,0x40,0x3d,0x1b,0x48,0x88,0xda,0xce,0xe8,0xd2,0xed,0xe0,0x6e,0x29,0xeb,0xdb,0x95,0x09,0xd5,0xc0,0xaa,0x2c,0x5c,0xac,0x46,0xeb,0xa4,0x35,0x2a,0xab,0x00,0x2e,0xc0,0x8b,0x42,0x65,0x2f,0x2f,0x13,0x84,0x60,0x15,0xa3,0x69,0xee,0xab,0x0e,0x50,0xbf,0x5f}},
|
||||
{{0x3a,0x79,0x39,0x60,0xe9,0x93,0xad,0x78,0xf9,0x0b,0x99,0x64,0x71,0x76,0xad,0xdc,0x63,0xa3,0x38,0xbf,0x0a,0x36,0x22,0xcf,0x4f,0x84,0x3e,0x34,0xaf,0x0b,0xd4,0x5c,0xc0,0xa4,0x01,0x7c,0x07,0xc3,0xb4,0xcb,0xdb,0x39,0xdd,0x39,0xc7,0x5c,0xbd,0xcf,0x61,0x8b,0x72,0x74,0xd6,0x85,0xdc,0x5c,0x08,0x93,0x6d,0xe6,0xf1,0xeb,0xb9,0x7c},{0x71,0x12,0x20,0xbb,0x37,0xa6,0xd8,0x71,0xf7,0x58,0xaa,0xbd,0x30,0xfb,0xac,0x94,0x62,0x45,0xf0,0x1a,0xc3,0x4a,0x07,0x78,0x6d,0x17,0xf5,0x8d,0x69,0x3d,0x2e,0x15,0x96,0x48,0x1a,0xb0,0x7e,0xdd,0xf5,0x2d,0xe1,0x56,0xfc,0xe9,0x26,0x91,0x51,0xfe,0x5e,0x2a,0xdc,0x23,0x89,0x09,0x14,0xe6,0x17,0xa9,0x14,0x8c,0x8c,0xe8,0xe3,0x71},{0xe4,0xd0,0xa7,0x5a,0xce,0x93,0x1d,0x55,0xa2,0x3d,0xdd,0x7e,0x10,0x66,0x6d,0xc6,0x5c,0x87,0x9f,0x7a,0x52,0x5e,0x76,0x3f,0x09,0x9e,0xe5,0x8e,0x60,0x39,0x5e,0x3c,0x28,0x31,0xa4,0x12,0x39,0xfd,0xba,0xda,0xc8,0x59,0xdd,0x5b,0x26,0x78,0x8f,0x33,0xd2,0xc8,0x22,0x77,0x49,0xcf,0x34,0x61,0xbe,0x7a,0xa6,0x31,0xbe,0xe5,0xab,0xc2},{0x60,0xf5,0x52,0xbd,0xb1,0x9e,0x06,0xa3,0x94,0xad,0xe0,0x82,0x33,0x7c,0x41,0x17,0x5b,0x8a,0xbc,0x7c,0xce,0xd1,0x7e,0xfd,0x39,0x17,0xfd,0x90,0x5a,0x53,0x89,0x27,0x9f,0x27,0x7a,0x08,0xb2,0x66,0xda,0xb5,0xbf,0x3b,0x80,0xe2,0x1a,0x30,0x80,0x45,0x13,0xf3,0x4b,0x0c,0x4a,0xe9,0x0a,0x6e,0xf2,0x3e,0xa3,0x70,0x3d,0x89,0xd3,0xb2},{0x23,0x41,0x08,0x8d,0xa8,0x0b,0x6a,0xe0,0x65,0xb1,0x42,0x50,0x49,0xdd,0xd3,0xe8,0x89,0x13,0x7a,0x04,0xf0,0xd6,0x2f,0x6e,0x73,0xcd,0xdc,0x10,0xbb,0x02,0x6b,0xa2,0x25,0x58,0xa3,0x08,0x37,0x7c,0x8b,0x1f,0x4a,0x81,0x38,0x88,0xbd,0xf4,0x4f,0x24,0xe8,0xd6,0x9f,0x2f,0x13,0xeb,0x79,0x60,0x80,0x90,0x52,0x6b,0x8e,0xed,0xcb,0x77},{0x5b,0x88,0x63,0xaf,0xf9,0xe2,0x44,0x23,0xc8,0x02,0xe0,0x22,0x15,0x3d,0x2a,0xb7,0x40,0x76,0xe8,0x95,0xfd,0xa9,0xe3,0x85,0x94,0xa3,0xbb,0xce,0x61,0x19,0x0d,0xe2,0x95,0xdf,0x81,0x11,0x53,0x77,0xcd,0xf2,0xd8,0x4f,0xbf,0x19,0x6a,0x3d,0x4b,0xda,0xa4,0x56,0xa4,0xcd,0x9d,0x4f,0x52,0x53,0x7d,0xd8,0xac,0xe0,0xfb,0x9a,0x71,0x0c,0x59,0xf9,0x0b,0x03,0xf1,0x7b,0xaf,0x33,0xc3,0xe5,0x1e,0x8d,0x4f,0xbe,0x21,0xed,0x6b,0x15,0xdd,0xd2,0xeb,0x7c,0xe4,0x59,0x6c,0xf9,0x91,0xc1,0x3a,0x3a,0xb6,0x2b},{0x5e,0x54,0xe5,0x1b,0x3d,0x2c,0x00,0x80,0xdd,0xe4,0x10,0x50,0x98,0xb6,0x0e,0x3a,0xf7,0xde,0x67,0x2c,0x8e,0x7b,0xb4,0x73,0x0b,0xc7,0x12,0xb0,0x66,0x6b,0x3b,0x99,0xd9,0x33,0x78,0x5f,0x45,0xe5,0xec,0x15,0x02,0xfa,0x8b,0x86,0xfd,0xe0,0xb7,0x84,0x72,0xf2,0x68,0x5c,0xd6,0x2e,0x37,0xe9,0x49,0x32,0x2f,0xcd,0xcd,0x1e,0x99,0x0f,0x59,0xf9,0x0b,0x03,0xf1,0x7b,0xaf,0x33,0xc3,0xe5,0x1e,0x8d,0x4f,0xbe,0x21,0xed,0x6b,0x15,0xdd,0xd2,0xeb,0x7c,0xe4,0x59,0x6c,0xf9,0x91,0xc1,0x3a,0x3a,0xb6,0x2b}},
|
||||
{{0xfc,0xb9,0x4e,0x4e,0x11,0xfe,0xe1,0xc5,0xc7,0x49,0x54,0xd2,0x2f,0x13,0x34,0x7c,0x91,0x7d,0x98,0x43,0xe4,0xb7,0x48,0xea,0xe8,0x26,0xcb,0x26,0x1f,0xe4,0x99,0x10,0xb9,0x34,0xc2,0xac,0xa3,0x2c,0xbd,0x9e,0x80,0xd4,0x12,0x3b,0xb3,0xf0,0x01,0xae,0x91,0x9f,0xba,0x77,0x32,0x4d,0x9d,0xac,0x1f,0x8d,0xad,0xa7,0x46,0x44,0x85,0xfb},{0x65,0x05,0x0b,0xd2,0x41,0xd3,0x58,0x2a,0x14,0xbc,0x7b,0x15,0x4a,0x6a,0x6a,0x18,0x71,0x09,0x25,0x33,0xac,0x73,0x53,0xab,0xd9,0x0d,0x8d,0xdf,0x95,0x59,0x7e,0x02,0x4c,0x03,0x11,0x5c,0xdc,0x80,0x19,0xd5,0x13,0x66,0x7f,0xf7,0xd7,0x23,0x18,0x40,0x84,0x16,0x6b,0x52,0x82,0x96,0x05,0x1b,0xfa,0xcb,0x4b,0x77,0x00,0x12,0xa0,0x28},{0x13,0xe0,0x16,0x1e,0x24,0x24,0xe9,0xde,0x9c,0x86,0xa9,0xcf,0x02,0x96,0xdf,0x8c,0x64,0xcb,0x3d,0x7d,0x8a,0x2a,0x73,0x18,0x20,0xc8,0xb0,0xac,0x10,0xa0,0x52,0x0c,0x6c,0x17,0xd9,0xbd,0x3c,0x3e,0xe5,0x0c,0x4a,0xdb,0x59,0xcc,0x59,0x15,0x08,0x1e,0xfe,0xaa,0xe3,0xd6,0xa1,0x37,0xd6,0xd5,0x6d,0x8e,0xcd,0x57,0xa9,0x81,0xb3,0x43},{0x46,0x28,0x2b,0xa0,0xe5,0xe3,0xf0,0x72,0xa7,0xbc,0x8d,0xec,0x45,0x31,0x6e,0xdb,0xb2,0x4b,0x20,0xbf,0x64,0x74,0x26,0x70,0x9b,0xd6,0xd3,0x7f,0x9f,0xc1,0x59,0x03,0x2d,0xda,0x6f,0xaa,0x7c,0x92,0xc6,0xe0,0xe8,0xaa,0x1e,0x26,0xf0,0x1e,0xcc,0xef,0x6d,0x87,0x04,0x3c,0xed,0x52,0x15,0xb3,0x9f,0x01,0x4e,0xe3,0x3c,0xb6,0xbb,0xac},{0x86,0x1a,0x25,0x8e,0x41,0x85,0xf9,0xba,0x98,0x15,0xb1,0xec,0x50,0xb4,0xd0,0xab,0x55,0x54,0xbb,0x3b,0x61,0xfc,0x54,0xf3,0x09,0xea,0xaa,0x6e,0xbf,0x03,0xc3,0x58,0x1d,0x24,0xb5,0xd5,0x45,0x5a,0x7a,0x14,0xc3,0x6a,0xa9,0xd8,0x6f,0x41,0xc3,0xb4,0x9a,0x05,0x71,0xbc,0x23,0x67,0xc2,0xa8,0xf5,0x7b,0x69,0xa5,0xe1,0x7a,0x35,0x1d},{0x3b,0xf5,0xa8,0xc0,0x2a,0x7d,0x85,0x88,0xd4,0xf4,0x26,0xd3,0xf4,0xe3,0x52,0x35,0x37,0x06,0x1e,0x71,0xc2,0x3b,0x7b,0xeb,0xf0,0x07,0x30,0x6b,0x37,0x31,0xb9,0x27,0xd8,0x0b,0x17,0xae,0xff,0xd4,0x7c,0x59,0xd7,0x2d,0xea,0xcb,0x92,0x2f,0x93,0xc7,0xd7,0xc3,0xaf,0x75,0x73,0x6a,0x3f,0x89,0xe5,0x13,0x0c,0x28,0x47,0xf4,0xa4,0x07,0xfb,0xd9,0x77,0xb4,0x1e,0xb2,0x70,0xca,0x85,0x22,0x58,0xc6,0x0b,0x19,0xc2,0xa5,0xba,0xc3,0xc9,0xb6,0x4a,0xdb,0x7d,0x4d,0x66,0xde,0xeb,0x8c,0x1a,0x23,0xb8,0x4c},{0x8c,0x57,0x0e,0x9f,0x0a,0xb2,0xf4,0x07,0xdd,0x7b,0x46,0xf8,0xa0,0xb1,0x33,0x4c,0x2b,0x1e,0x1a,0xe0,0x28,0x17,0x14,0xba,0x14,0x06,0x40,0x1f,0x30,0x0a,0x19,0xcd,0xe7,0xca,0xfb,0xdb,0xb9,0x76,0xf8,0x8a,0x81,0x3d,0x03,0x86,0x7e,0x66,0x75,0x1d,0xec,0xff,0x6b,0xa7,0xea,0x4c,0x8c,0x60,0xd2,0x1f,0x72,0x11,0x4c,0x5d,0xeb,0x01,0xfb,0xd9,0x77,0xb4,0x1e,0xb2,0x70,0xca,0x85,0x22,0x58,0xc6,0x0b,0x19,0xc2,0xa5,0xba,0xc3,0xc9,0xb6,0x4a,0xdb,0x7d,0x4d,0x66,0xde,0xeb,0x8c,0x1a,0x23,0xb8,0x4c}},
|
||||
{{0x05,0x64,0x16,0x53,0xbb,0xb2,0x6e,0x81,0xfc,0xe6,0xec,0xc8,0x0c,0xc1,0x75,0x59,0x23,0xe2,0x4b,0xd8,0x6a,0x70,0x34,0x50,0x37,0xc6,0xc2,0xbd,0x27,0xfd,0xad,0x4c,0xee,0xe4,0xf7,0xfc,0x91,0x05,0x48,0x3c,0xd4,0x09,0x78,0x00,0xce,0x15,0x37,0xdc,0xe7,0xce,0x48,0x09,0x3e,0x7f,0x01,0x9b,0x03,0xc8,0x2f,0x9b,0xe6,0x42,0xe1,0x71},{0x64,0xbf,0x63,0x91,0xe5,0x3e,0x90,0x89,0x96,0xea,0x59,0x51,0x60,0x7b,0x5f,0xfe,0x0f,0x76,0x86,0x19,0x45,0x82,0xd9,0x5e,0x1a,0xd1,0xf6,0x04,0xc6,0xaa,0x71,0xda,0x80,0xed,0x75,0x51,0xc8,0x9a,0x27,0x09,0xc3,0x50,0xe4,0x14,0xa1,0xc3,0xf8,0x3a,0x6c,0x84,0xff,0x87,0xd5,0xf0,0xb0,0x3c,0x5a,0x57,0x14,0x90,0xc7,0x31,0xf8,0x47},{0x88,0x7d,0xcc,0x81,0x2b,0xbb,0x7e,0x96,0xbe,0x78,0xe1,0xb1,0xf2,0xed,0x6f,0xd8,0xff,0xbd,0x7f,0x8e,0xe5,0xeb,0x7f,0x7b,0xca,0xaf,0x9b,0x08,0x1a,0x77,0x69,0x1d,0xc2,0xa4,0x7c,0x4d,0xa6,0x74,0x8e,0x33,0x24,0xff,0x43,0xe1,0x8c,0x59,0xae,0x5f,0x95,0xa4,0x35,0x9e,0x61,0xb8,0xcc,0x4c,0x87,0xb9,0x76,0x53,0x20,0xa3,0xf3,0xf5},{0x13,0x2a,0xcc,0x07,0xb1,0x5f,0xc7,0xf1,0x08,0x0e,0x7d,0x7e,0x26,0x56,0xd8,0x16,0x9c,0xae,0xac,0xc4,0xf5,0x9c,0x15,0x67,0xae,0xc4,0xcc,0x3f,0xc0,0xaf,0x53,0x28,0x1f,0x65,0x14,0xe5,0x7f,0x0c,0xf5,0x7a,0xe3,0x93,0xc1,0xa3,0xd1,0x4a,0x09,0x7d,0x24,0xab,0x22,0xc4,0xc4,0xce,0x85,0x37,0x86,0xa8,0x9c,0x39,0x33,0xba,0x1b,0x83},{0x6d,0x3e,0x92,0x5a,0xa8,0xfa,0xe6,0x71,0x98,0xa8,0x82,0x38,0xcc,0xed,0xd6,0x92,0x7e,0x3e,0xcb,0xb2,0x82,0x92,0x7a,0x56,0x9e,0xd6,0x29,0x45,0x42,0x04,0x76,0x82,0xa5,0xfc,0xd9,0x0c,0x12,0x4c,0x98,0x04,0x2a,0x3a,0x98,0x01,0xb8,0x62,0xe8,0xe6,0x7c,0x51,0xe3,0x7d,0x97,0xf5,0x45,0xb4,0x13,0xdf,0x15,0x68,0xc3,0x00,0x75,0x40},{0x7e,0x89,0x3d,0x7c,0x78,0x36,0x3c,0x85,0xda,0xb6,0x9b,0x6d,0xbc,0x52,0x7d,0xc6,0xaa,0xfd,0x90,0x62,0xe4,0xc4,0x1a,0x5a,0x2e,0xa1,0x57,0xd7,0xda,0x57,0xf4,0x58,0xc5,0x23,0x61,0x21,0xe1,0x93,0xfa,0x06,0x22,0xed,0x41,0x66,0x24,0x47,0xb9,0xed,0xc8,0x84,0x25,0x28,0x39,0xec,0xfb,0x29,0xa1,0xcd,0xe1,0x9d,0x02,0x48,0x6f,0x0a,0xe2,0x9f,0x98,0xfd,0x3d,0x18,0xa1,0x24,0x9c,0xc6,0x75,0xb8,0x99,0x76,0x2a,0xa4,0x9e,0xb1,0x97,0x2d,0x1c,0x99,0x65,0x5f,0x1f,0xda,0x14,0x4f,0x10,0x49,0xf1,0x7a},{0x2c,0xec,0x27,0x63,0xd2,0x77,0x14,0x2d,0x01,0x18,0x10,0xe0,0x23,0x1b,0xa2,0x25,0x61,0xd4,0x52,0xd9,0x90,0xde,0x97,0x7e,0xb8,0xfa,0x38,0x25,0xf2,0x91,0x07,0x3e,0xc4,0xa9,0x3e,0xb5,0x67,0x02,0x28,0x94,0x5c,0x34,0xa1,0x0a,0x5c,0x54,0x53,0xd9,0xb4,0xc4,0x5a,0x8e,0x57,0x18,0xc3,0x35,0xea,0x47,0x75,0xe0,0x44,0x01,0x71,0x09,0xe2,0x9f,0x98,0xfd,0x3d,0x18,0xa1,0x24,0x9c,0xc6,0x75,0xb8,0x99,0x76,0x2a,0xa4,0x9e,0xb1,0x97,0x2d,0x1c,0x99,0x65,0x5f,0x1f,0xda,0x14,0x4f,0x10,0x49,0xf1,0x7a}},
|
||||
{{0x41,0x10,0xd9,0x7f,0xb8,0x83,0x9e,0x42,0x43,0x7a,0xb0,0x6d,0xa6,0xcf,0xa5,0x7a,0x50,0x93,0x2d,0x13,0x94,0x37,0xa8,0x92,0x26,0x1f,0xad,0xe0,0x25,0x19,0x91,0x62,0x28,0xfb,0x18,0xbf,0x89,0xb0,0x42,0x80,0x14,0xcd,0xd2,0x72,0x84,0x1c,0xfd,0xe5,0xc3,0x71,0x3c,0x3f,0x12,0x5e,0xdd,0x53,0x39,0xf6,0x4b,0x9f,0xb3,0x5c,0xe3,0x15},{0xd0,0xc7,0x18,0x4d,0x68,0x9f,0xdd,0xec,0x81,0xf8,0xc6,0x0e,0x83,0x43,0x23,0x3d,0xfc,0xf3,0x66,0x55,0xa8,0x65,0x8b,0xd7,0x9b,0x3c,0x74,0x23,0xcd,0xae,0x60,0xe7,0x61,0xed,0x2c,0x7e,0xe7,0xa7,0x63,0x7d,0x72,0x47,0x6a,0x33,0x1c,0xaa,0x81,0xba,0x6f,0xd4,0x00,0xe7,0xa9,0x58,0xb2,0xad,0xee,0x3f,0x9c,0x70,0xff,0x2f,0x13,0x6f},{0x56,0x7b,0x19,0x66,0x42,0x9a,0x99,0x51,0x23,0x4f,0xb6,0xe7,0xcf,0x98,0xff,0x20,0x5a,0xc3,0x0e,0x36,0xc9,0xc6,0x20,0x25,0x0c,0x56,0x98,0xfb,0xbd,0xd6,0x66,0x4f,0x6f,0x94,0x85,0x8a,0x35,0xf3,0x50,0xad,0x87,0xde,0x95,0x9e,0xae,0x2a,0xd8,0xdd,0x78,0x87,0x96,0x2b,0xe0,0x12,0x95,0xd9,0x3b,0xb2,0x2a,0x06,0xe2,0xf0,0x06,0xd4},{0x42,0x24,0xdd,0x0a,0xd1,0x11,0x31,0x7e,0x56,0x45,0xb0,0x0e,0x86,0xc1,0x5d,0x8c,0x03,0x01,0xb8,0x33,0x20,0xbd,0x08,0x10,0xe5,0x70,0x92,0x2b,0x5b,0x86,0xd3,0x50,0x4c,0x1e,0xe3,0xd1,0x2a,0x4e,0x40,0x02,0x19,0x0b,0xf6,0x91,0xd9,0x9e,0xaa,0x54,0x7c,0x3d,0xba,0xc5,0x5a,0x9e,0xb2,0xbb,0x4e,0x0d,0x5b,0xdd,0x90,0xc9,0x7b,0xc2},{0x54,0x95,0xd5,0xdc,0x7e,0x7e,0xec,0xd4,0x67,0x08,0xdc,0x58,0xa9,0x80,0x8a,0x03,0x6a,0xf8,0x40,0xca,0x0d,0x5b,0x6c,0xe4,0xc9,0x71,0xa5,0xaf,0x2a,0xaa,0xe8,0x95,0x45,0xe7,0xe2,0xc3,0x47,0x84,0xc6,0xbe,0xe5,0x65,0xaf,0xcd,0x7c,0x20,0x5f,0x8b,0x19,0x61,0xe4,0xc9,0xc1,0x86,0xa5,0x6f,0x96,0xf3,0x9c,0x13,0x28,0x1b,0xcf,0x07},{0xc4,0x7f,0xf2,0x6f,0xcc,0x4a,0xf8,0xa4,0x1f,0x1d,0x6e,0x5e,0x30,0xb2,0x99,0x8f,0x5d,0x7c,0x26,0x1c,0x52,0x6f,0xd0,0x33,0xa7,0xf8,0xca,0x2a,0xc3,0x8c,0xa8,0xd1,0x50,0x4f,0xa7,0xe8,0xf2,0x10,0x4c,0xcd,0x8a,0x31,0x03,0xc8,0x93,0x2c,0xd7,0xe4,0x21,0xdb,0xa2,0x62,0x7b,0x1f,0x28,0x14,0x69,0x7e,0x87,0xac,0xf9,0xb4,0x97,0x00,0x62,0x86,0x14,0xd7,0xe4,0x65,0xdd,0x9e,0x1c,0x64,0x5f,0x3e,0xef,0xfe,0xa6,0x60,0x68,0x91,0x94,0x8a,0x1c,0x89,0xae,0xe4,0xcf,0x3a,0xdd,0xc0,0xb4,0x47,0xe8,0x8f},{0x12,0x80,0x00,0xda,0xce,0xc4,0x80,0x8f,0xa9,0xa1,0x5d,0x98,0x7d,0x2c,0xb2,0x9c,0x71,0xde,0x62,0x89,0x6a,0xe1,0x92,0xd7,0x96,0xdc,0xcd,0xc8,0x08,0x0e,0x48,0xbf,0x2a,0x53,0x72,0x90,0x31,0x71,0x49,0x02,0xda,0x4e,0x19,0x05,0x10,0xcb,0x41,0x97,0x44,0xdc,0x2d,0x1e,0x48,0xe5,0x0e,0x41,0x9d,0x7d,0x03,0xa3,0xe2,0x65,0xd4,0x01,0x62,0x86,0x14,0xd7,0xe4,0x65,0xdd,0x9e,0x1c,0x64,0x5f,0x3e,0xef,0xfe,0xa6,0x60,0x68,0x91,0x94,0x8a,0x1c,0x89,0xae,0xe4,0xcf,0x3a,0xdd,0xc0,0xb4,0x47,0xe8,0x8f}},
|
||||
{{0x00,0x4b,0x0b,0xf5,0x1f,0x07,0x1e,0x23,0xe3,0x93,0x7b,0x31,0x41,0x2a,0x0a,0x50,0x35,0xe2,0xbb,0xfe,0x51,0x77,0x6c,0xc9,0xc5,0x13,0xb9,0x87,0x79,0x65,0x68,0x20,0xcc,0x09,0x90,0xa9,0xe4,0xef,0x9f,0x1a,0xe1,0x69,0x76,0x14,0x82,0x42,0x88,0x4b,0xdc,0xe0,0x10,0x22,0xe2,0xd6,0x36,0x7c,0x0b,0xd9,0x08,0xea,0xfa,0xe4,0xfd,0x45},{0x57,0x5c,0x1e,0x20,0xb4,0xae,0x9e,0x9d,0x04,0xfb,0x1a,0xd7,0x23,0xd8,0x8a,0x6b,0x1b,0xb2,0xef,0xa9,0x06,0x38,0xbb,0x9b,0x43,0x2e,0xf1,0x81,0x0b,0x76,0xec,0x20,0x46,0x1b,0xc4,0x71,0x19,0x3e,0x79,0xe8,0xcf,0xea,0xdc,0x4b,0x3f,0x0b,0xeb,0x05,0x13,0x1a,0x2c,0xfe,0x16,0xe9,0xf0,0xc4,0x9c,0x41,0xab,0x45,0x1b,0xba,0x05,0xec},{0x06,0x0b,0x73,0xec,0x30,0x74,0x0d,0x8d,0x13,0x4b,0xef,0xac,0x3b,0x05,0xb6,0xed,0x2b,0x05,0xd1,0xa7,0x65,0xb0,0xcb,0x69,0x00,0xeb,0x47,0xe3,0x1c,0x07,0x8b,0x15,0xbf,0x69,0xff,0x27,0xb4,0xdb,0x77,0xaf,0xe9,0x9a,0xfb,0xb2,0x28,0xa4,0xf9,0x05,0xe4,0x3c,0x66,0x56,0x00,0x1a,0x2c,0x41,0xf2,0xe1,0x11,0x09,0xfa,0xe1,0x50,0x49},{0xbc,0x4d,0x6f,0x75,0x79,0x77,0x64,0x6b,0xec,0xac,0x1a,0x26,0x73,0x9c,0xf3,0xf1,0x4d,0x79,0xbe,0x6f,0x0c,0x07,0x22,0xd1,0xa1,0x31,0x75,0xa8,0x9c,0xb6,0x00,0x63,0x0d,0x40,0x17,0xec,0x83,0xda,0x82,0x2c,0x3b,0xfd,0x90,0xe3,0xbc,0xc2,0x2c,0xf5,0x3e,0x41,0xe9,0x98,0x57,0xa2,0xb7,0xce,0x5f,0x31,0xbb,0x0b,0x05,0x61,0x0f,0x55},{0xb7,0xab,0xb2,0x84,0xf1,0x67,0x24,0x16,0x61,0xe9,0x20,0x33,0x0b,0xff,0x22,0x61,0x70,0xa0,0x5d,0xf6,0xa8,0x33,0xc9,0x30,0x73,0xe5,0x89,0x36,0x59,0xea,0xa8,0xe7,0x03,0xf6,0x14,0xc1,0x79,0xb6,0x42,0xa5,0xc8,0x6c,0xb8,0x94,0x29,0x24,0x00,0x09,0xb5,0x54,0x3f,0xe1,0x6b,0xfb,0x4d,0x2d,0xa9,0x9a,0x02,0xa1,0xa5,0x09,0xf4,0xcb},{0x92,0xfa,0x18,0x84,0x3e,0xdb,0xdf,0x7d,0x87,0xd6,0x2d,0x07,0x05,0x2c,0xba,0xe4,0x30,0x76,0xa2,0xe8,0x71,0x3b,0x1b,0x93,0x5b,0xce,0x2e,0xec,0x50,0x6e,0x4a,0x0b,0x2d,0xbe,0xa3,0x76,0x92,0xf8,0xc8,0x4a,0x71,0x66,0xec,0xfa,0x36,0xc5,0xdb,0xab,0x99,0x9c,0xbf,0x99,0x07,0xe8,0xfe,0xf4,0x2f,0x90,0x16,0x5d,0xdc,0xbe,0xfa,0x08,0x93,0xde,0x13,0xf5,0x32,0x45,0x9a,0xde,0xa2,0x5d,0xb9,0xe0,0x38,0x4c,0x6a,0xcc,0x13,0x46,0x27,0x28,0xbf,0xf8,0x7a,0x9c,0x2e,0xde,0x6f,0xfe,0xe1,0x86,0x41,0x79},{0xa7,0x32,0x52,0x76,0x4f,0x3e,0x1b,0xab,0x82,0x18,0x14,0xe7,0x42,0x32,0xb8,0xa4,0x98,0xde,0xa4,0xd7,0xae,0x42,0x84,0xda,0x71,0xf7,0x78,0x40,0x56,0x94,0x64,0x49,0x34,0x37,0xeb,0xe3,0x05,0x4c,0xb9,0xbb,0xce,0xb2,0x72,0xc0,0x75,0x1c,0xc4,0xd5,0x1e,0x3a,0xc1,0x43,0xda,0xd1,0x81,0x82,0xa9,0xd5,0x0e,0x0a,0x5e,0xc2,0xd7,0x04,0x93,0xde,0x13,0xf5,0x32,0x45,0x9a,0xde,0xa2,0x5d,0xb9,0xe0,0x38,0x4c,0x6a,0xcc,0x13,0x46,0x27,0x28,0xbf,0xf8,0x7a,0x9c,0x2e,0xde,0x6f,0xfe,0xe1,0x86,0x41,0x79}},
|
||||
{{0xa3,0xdf,0x4a,0xfd,0xe6,0x74,0xb8,0xeb,0xed,0xe7,0x7e,0xd2,0xae,0xf8,0x40,0x80,0x3a,0x55,0x58,0x1d,0x6b,0xa4,0x32,0x6c,0x15,0xbb,0x67,0xdf,0x9e,0xb5,0x70,0x4b,0x7f,0x4d,0xfe,0x34,0x42,0x0c,0x4d,0xe3,0x97,0x87,0x6d,0x08,0xe8,0x4d,0x8a,0xa9,0xbc,0xbf,0x1b,0xb7,0x66,0x32,0xf4,0x7f,0x93,0xca,0xa4,0xd2,0x8f,0x02,0x7b,0xfa},{0xea,0xac,0xdf,0x25,0x39,0xf3,0x28,0xb6,0xbe,0xa8,0x4a,0x32,0x59,0x4b,0x4f,0xb5,0xd2,0xf7,0xf5,0x75,0x43,0x8b,0xb3,0x6a,0x98,0x8c,0x14,0xc9,0x3f,0x7e,0x5c,0x05,0xf0,0xeb,0x1d,0xc5,0xe6,0x1b,0x5d,0x7f,0x38,0x5d,0x9a,0xbe,0xc8,0x97,0x09,0x65,0x62,0x88,0x99,0xda,0x95,0x13,0x93,0xd9,0xa3,0x19,0x0a,0xa7,0x4a,0xb2,0x81,0xa4},{0x6e,0x70,0x65,0xaa,0x1b,0x16,0xcb,0xc1,0x59,0x6b,0xc9,0x4d,0xd1,0x0a,0x9d,0x8c,0x76,0x70,0x3c,0xc1,0xc1,0x66,0xa6,0x9f,0xfc,0xca,0xb0,0x3f,0x0e,0xe9,0xa9,0x36,0x09,0x4f,0x94,0xf3,0x32,0x25,0x34,0xf6,0xe4,0xf9,0x0b,0x0c,0xe6,0xe0,0x6d,0x9e,0xa5,0x52,0x82,0x9c,0xd4,0x43,0xa4,0xd1,0xd1,0x63,0x20,0xce,0xbc,0x4f,0x43,0xdc},{0x35,0xd6,0xc1,0x68,0xa6,0xd7,0xd3,0x36,0x82,0x2a,0x0f,0x29,0x3e,0xd6,0x15,0x29,0x19,0x73,0x14,0x78,0x87,0x86,0xca,0x9f,0x6e,0x17,0xea,0xaf,0x24,0x37,0xd6,0xb4,0xb0,0xee,0x84,0x90,0x2d,0x18,0xbd,0x26,0xc3,0xd4,0x39,0x4f,0x45,0xfa,0x2f,0x70,0xf2,0xe2,0x2a,0x2a,0x5c,0x65,0x15,0xcb,0xaf,0x92,0x9a,0xfc,0x06,0xe0,0x8a,0x1b},{0x5d,0xfa,0xc0,0x2b,0xc3,0x94,0x19,0xb4,0xd6,0x13,0xe3,0xcf,0x91,0xad,0x8c,0xe1,0x97,0x46,0xfe,0xea,0x74,0xe0,0x0c,0x03,0xf7,0x2e,0x51,0xa7,0xf2,0xbc,0xce,0xe8,0x6b,0xfd,0x2f,0x54,0x52,0x12,0x00,0x8d,0x95,0x91,0xc3,0xf6,0x25,0xf8,0x65,0x6a,0x9c,0x79,0x6b,0x71,0xc0,0x0c,0x29,0xfb,0xe7,0x14,0x9f,0x2f,0x1a,0x07,0x53,0x50},{0xe9,0xd4,0x46,0x0b,0x51,0x3f,0xf1,0xbe,0x0a,0x23,0xa5,0x38,0xa0,0xe3,0x70,0x14,0x63,0xf0,0x94,0xbb,0x1c,0x4f,0x23,0x05,0x1b,0x62,0x40,0x9b,0xf9,0x52,0x1b,0x41,0x51,0x57,0x2a,0x99,0x73,0xda,0xe1,0xcf,0xc5,0x4c,0x65,0x3a,0xc2,0x9d,0x73,0xda,0xc9,0x59,0xf1,0xdf,0xab,0x2b,0x27,0xe1,0x59,0x8b,0xa7,0x48,0xf9,0x36,0xcb,0x08,0xe3,0x5e,0x1d,0xdd,0xf9,0x20,0x4f,0x64,0xa9,0x26,0x74,0x97,0xf2,0x2d,0x31,0xac,0x8c,0x20,0x77,0x09,0xa9,0x8f,0xed,0x23,0x77,0x7e,0xd7,0x34,0x93,0x84,0xe7,0xaa},{0xaa,0xf7,0x64,0xdf,0x34,0x59,0x1c,0x2c,0xbc,0x47,0x08,0x6a,0x25,0xbf,0x9d,0x48,0x54,0xcf,0xa0,0x6c,0xfc,0xd4,0x10,0x39,0x9f,0x64,0x46,0xce,0xd9,0x95,0x28,0x89,0xdf,0x94,0x5e,0x74,0x0b,0x55,0x46,0x82,0xd9,0x3d,0x82,0x97,0x7d,0xd0,0x3e,0xd7,0xf6,0x6f,0xaa,0x97,0x3e,0xdf,0xa7,0xde,0xe3,0xc5,0xaf,0xd3,0xa0,0x5a,0x30,0x0d,0xe3,0x5e,0x1d,0xdd,0xf9,0x20,0x4f,0x64,0xa9,0x26,0x74,0x97,0xf2,0x2d,0x31,0xac,0x8c,0x20,0x77,0x09,0xa9,0x8f,0xed,0x23,0x77,0x7e,0xd7,0x34,0x93,0x84,0xe7,0xaa}},
|
||||
{{0x96,0x4e,0xf2,0x1e,0x3a,0xe5,0x77,0xbf,0xa7,0x1c,0x3d,0x66,0x08,0x06,0xca,0x55,0x43,0x7a,0x08,0xf8,0xff,0x55,0xb3,0xbc,0x9a,0x83,0x9a,0x2e,0xe6,0x97,0x14,0x32,0x36,0x57,0x5c,0xa4,0x04,0x78,0xb1,0x92,0xf4,0x23,0x94,0xe6,0x2a,0xef,0xd4,0xe7,0xc4,0x02,0x9f,0xa9,0x79,0x77,0x61,0x90,0xd6,0xdb,0x6e,0x28,0x7e,0xc0,0x1d,0x70},{0xc5,0xd1,0x5c,0x34,0x15,0xa9,0x1e,0x42,0x2a,0x1b,0x0d,0xf0,0x56,0x83,0x10,0xc3,0xc9,0x21,0xfd,0x05,0xfa,0x51,0x0e,0x11,0x28,0xcc,0x84,0xac,0x35,0xb5,0xd8,0xc8,0x5c,0x80,0x11,0x1f,0x60,0x1c,0x72,0x25,0x82,0x45,0xb5,0x4f,0x66,0x6b,0x52,0xb1,0xf7,0x28,0x0f,0x80,0x76,0x44,0xdc,0x15,0x70,0x39,0xe9,0xaf,0xc7,0x0a,0xa0,0x43},{0xff,0x20,0x5e,0x3b,0x75,0xe9,0x38,0x7c,0xa3,0x5c,0x8b,0x1a,0xec,0x17,0x8d,0xf0,0xef,0xb3,0x53,0x9b,0x16,0xa9,0x44,0xf9,0x34,0x45,0x13,0x66,0x80,0x24,0xdc,0x22,0x0e,0x51,0x94,0xed,0xe6,0x83,0x36,0x32,0x63,0x23,0x1b,0xf8,0x78,0xb4,0x04,0x7f,0x5a,0x50,0x54,0x12,0x19,0x04,0x61,0xdd,0x25,0xf0,0x48,0x29,0x04,0xc1,0x44,0xe2},{0x46,0x32,0x2d,0xc7,0xbc,0x05,0x2a,0xd3,0xb5,0xce,0x7d,0x47,0x5e,0xfc,0x90,0x38,0xef,0xfa,0x6f,0x42,0xf0,0x66,0x05,0x89,0x7c,0x9a,0xc1,0xfd,0xa2,0xe8,0xa7,0x38,0x18,0x6d,0x7f,0x9e,0xfb,0xbd,0x06,0x0c,0x70,0xd7,0x29,0x10,0x88,0x04,0x9f,0x24,0x28,0x9d,0xc7,0x84,0xdf,0xb6,0xec,0xb2,0xc7,0x1b,0xd1,0xc1,0x9d,0x56,0xb0,0x83},{0xda,0xd7,0x34,0xee,0x62,0x13,0x8f,0x47,0xad,0xb4,0x9c,0x98,0xe4,0xc5,0xb3,0x29,0x31,0x11,0x64,0xad,0xf5,0x0b,0x60,0xe1,0x0e,0x18,0x28,0x30,0x3c,0xa2,0xe3,0x29,0x89,0x0a,0x7e,0x18,0xba,0x30,0x9e,0x7d,0x53,0xf1,0x82,0xd5,0x27,0xe5,0xf3,0xab,0x15,0xcd,0x62,0x7e,0xdf,0xf0,0x0e,0x42,0xfa,0x6b,0x7b,0x54,0xd2,0x74,0x19,0x8f},{0x29,0x4d,0x28,0x80,0x62,0xb5,0x77,0xbb,0x69,0x70,0xb0,0xb7,0x10,0x2e,0xed,0xfc,0x13,0x34,0x93,0x7f,0xd8,0xfc,0xb5,0x7b,0xfe,0x34,0x0a,0xa3,0x95,0x5b,0xb1,0xa7,0xc6,0xab,0x82,0x79,0x25,0x23,0x94,0x12,0xa4,0x34,0xec,0x23,0xca,0xcb,0xd0,0xa3,0xf9,0x31,0x32,0xce,0x50,0x31,0x73,0x23,0x98,0x94,0xe3,0x08,0xd9,0x1e,0xc3,0x0b,0x39,0xe3,0x3b,0xf2,0xe8,0xb7,0x26,0x28,0x9d,0xb3,0x12,0x8d,0x16,0xca,0x89,0x26,0xa9,0x1c,0xa3,0x1f,0x36,0x10,0x60,0x6a,0x29,0x85,0xe7,0x2c,0xee,0xc1,0xb6,0xae},{0x68,0xed,0x3c,0x64,0xe6,0x87,0xf0,0x14,0x64,0xfc,0x38,0x3a,0x0f,0xd9,0x7a,0x5b,0x52,0x32,0x10,0xca,0xc6,0x83,0x0b,0xae,0x17,0x0e,0xfe,0x77,0xe0,0xe7,0x83,0xa1,0x2c,0x78,0x62,0x9c,0x79,0x08,0x2b,0xd4,0x85,0x72,0x27,0x8d,0x97,0x78,0x62,0x33,0x34,0xeb,0x5c,0xde,0x5d,0xaa,0x4d,0xfa,0xd1,0x67,0xa4,0xea,0x45,0xad,0xf9,0x06,0x39,0xe3,0x3b,0xf2,0xe8,0xb7,0x26,0x28,0x9d,0xb3,0x12,0x8d,0x16,0xca,0x89,0x26,0xa9,0x1c,0xa3,0x1f,0x36,0x10,0x60,0x6a,0x29,0x85,0xe7,0x2c,0xee,0xc1,0xb6,0xae}},
|
||||
{{0xd9,0x64,0xb2,0xe1,0x9f,0x0a,0x35,0xfc,0x9f,0xc3,0xa5,0x2a,0xa3,0x84,0xb4,0xf3,0x23,0xc4,0xf3,0x5a,0x9d,0xf8,0x7f,0x35,0xa9,0xf5,0x5b,0x68,0xfc,0x19,0x69,0x63,0x6a,0x13,0x19,0x32,0xcc,0x9d,0x0c,0x3c,0x7d,0xdd,0x85,0x16,0xa8,0xd9,0x2b,0x75,0x08,0x4b,0x9a,0xa5,0x6e,0xf3,0xe9,0xeb,0xed,0x5d,0x2e,0xfd,0x2e,0x0c,0x60,0xa2},{0x0f,0xf6,0x8c,0x3f,0x6e,0xee,0x56,0x4f,0x43,0x6f,0x54,0xbd,0x7a,0xe4,0xbe,0xa8,0x77,0x05,0x99,0xe7,0x9e,0x59,0x22,0x85,0x9b,0xc6,0xe4,0x2a,0x61,0x9c,0x19,0xb1,0x5a,0xeb,0x7a,0xf8,0x41,0x4e,0xe5,0x2a,0xd0,0xf7,0x44,0xf0,0x16,0xea,0x0c,0x04,0x19,0x6c,0xb6,0x30,0x3c,0x6e,0x2d,0x79,0x9a,0x8f,0x08,0x90,0x11,0xf1,0xc0,0x4d},{0x68,0xe7,0x1d,0x40,0xf1,0x07,0xc0,0xc6,0xb2,0x87,0x9c,0xa2,0x19,0x43,0x7a,0xdf,0x8a,0x5a,0x0f,0xe2,0x24,0x97,0xa0,0x38,0x79,0x20,0x38,0xa9,0x9c,0x77,0xc4,0x37,0xa6,0x02,0xe0,0x93,0x47,0xa4,0x55,0x21,0xc2,0x69,0xbe,0x09,0x05,0xaa,0x87,0x28,0xf1,0x95,0x2f,0xdb,0xf0,0xbf,0xd2,0x9e,0x5e,0x3a,0xfa,0xc6,0x2f,0x13,0x09,0xaf},{0xe1,0x9e,0xc8,0x4f,0xc9,0xdd,0x61,0x60,0x94,0xbc,0xd3,0xd6,0xde,0x11,0x6e,0xec,0x84,0xc4,0xdd,0xbe,0x20,0x46,0x6c,0xef,0xf6,0x9d,0x37,0x07,0x53,0x72,0x57,0xf9,0x02,0xb5,0x64,0x1f,0xe2,0x56,0xa4,0x38,0x6d,0xa4,0xed,0x23,0x9e,0xa3,0xf4,0x4d,0x77,0x52,0xdc,0x8c,0x51,0xfc,0x88,0x18,0xbc,0x83,0x2a,0xac,0xc1,0x1d,0x3d,0x59},{0x08,0x4f,0x78,0x21,0xfd,0x4b,0x85,0x86,0x4e,0x25,0xdd,0x47,0x60,0x7f,0x7e,0xc6,0xd3,0xa1,0xab,0x91,0x3f,0xeb,0xf6,0x40,0x7e,0x1b,0xbd,0x99,0x9c,0x7c,0x2f,0x4f,0xca,0x68,0xa5,0xf6,0x8c,0x1e,0xcb,0xb8,0x76,0xe2,0x87,0x5b,0x49,0x68,0x97,0x2c,0x21,0x5c,0x7c,0x93,0x79,0x9a,0x95,0xa1,0x3a,0x49,0xc9,0x6d,0x34,0x6b,0xa1,0x98},{0xb9,0x88,0x25,0x9a,0x3b,0x53,0x56,0xa1,0x48,0x0f,0xf0,0x92,0xde,0x4e,0x3e,0x3a,0xcf,0x02,0xdc,0x5c,0xc2,0xc3,0x78,0xad,0x8a,0x0c,0x3c,0xc7,0xdd,0xdd,0x71,0x6e,0x3f,0xd9,0x3a,0x57,0x2a,0x19,0xa5,0x3b,0x5c,0x46,0x7b,0xc9,0x0f,0x16,0xb3,0x58,0xa6,0x85,0xfa,0x91,0x2c,0x9a,0x9c,0x12,0xb6,0xd6,0x7d,0x9a,0xf0,0x9d,0xe9,0x02,0xad,0x12,0x87,0xda,0x85,0x58,0x6b,0xff,0x68,0x96,0x05,0x33,0xba,0x7f,0x08,0xf9,0xa9,0xa2,0xa9,0x46,0x43,0xe5,0x03,0x12,0xe4,0xbe,0x74,0xaa,0x46,0x4e,0x51,0xb3},{0x61,0x70,0x17,0x50,0x26,0xfa,0x51,0x83,0xe0,0xca,0xa9,0xb1,0xc3,0xc4,0x83,0xa9,0xb6,0x43,0x6b,0x7a,0x5b,0xe4,0x21,0x5a,0x6b,0xd4,0x34,0xf8,0xee,0x95,0x86,0x2d,0x03,0xbf,0xca,0xd0,0xfa,0x68,0x53,0xb2,0x97,0x50,0xad,0x89,0x2f,0x99,0x63,0x67,0x18,0x57,0x1f,0x57,0x41,0xbc,0xb7,0xc0,0x18,0xe7,0xb6,0xf3,0x0f,0xc4,0x49,0x0d,0xad,0x12,0x87,0xda,0x85,0x58,0x6b,0xff,0x68,0x96,0x05,0x33,0xba,0x7f,0x08,0xf9,0xa9,0xa2,0xa9,0x46,0x43,0xe5,0x03,0x12,0xe4,0xbe,0x74,0xaa,0x46,0x4e,0x51,0xb3}},
|
||||
{{0xc5,0xdf,0x86,0x8f,0xf1,0xa7,0xad,0x57,0xfd,0xb4,0x53,0xc3,0x92,0x1b,0x9e,0x2e,0xdd,0xc5,0xa4,0x3b,0x72,0xa6,0x9b,0x4a,0x15,0xca,0x35,0xed,0x3c,0x1a,0x3b,0x38,0x36,0xd6,0xf2,0x03,0xb6,0x97,0x1f,0xcb,0x40,0x5d,0x3c,0x25,0xfc,0xe7,0xff,0xc6,0xbe,0x61,0xe1,0x98,0x31,0x13,0xa9,0xbe,0x05,0x86,0xfe,0x5c,0xf6,0xcc,0xaa,0xf5},{0xd2,0x57,0x19,0x98,0xf8,0x74,0x90,0xb7,0x69,0x6e,0xdd,0x44,0xf1,0x8b,0xb1,0x9c,0xfd,0x5b,0x6b,0xc0,0x45,0xf2,0x49,0xa5,0x4b,0xff,0x8b,0x7f,0x87,0xe3,0xf9,0x71,0xab,0xfa,0xc8,0x17,0xed,0xeb,0x19,0xc6,0x3c,0xee,0x78,0xba,0x89,0x97,0x49,0x85,0x39,0x68,0x29,0x88,0x0b,0x1c,0xd1,0x42,0x8b,0xe8,0x1a,0x3b,0xeb,0x4d,0xef,0x3b},{0xea,0xfb,0xec,0x27,0xc3,0x92,0xc3,0x68,0x0d,0x3c,0x5b,0x20,0x20,0x9c,0x96,0xa7,0x39,0xfa,0x80,0x91,0xef,0x86,0x7d,0xa8,0x87,0xf6,0xef,0x14,0x01,0x46,0xf0,0x68,0x0a,0x8b,0xae,0x83,0x91,0x7e,0xa0,0x14,0x14,0xde,0xf9,0xa8,0xfd,0x67,0x57,0x17,0x20,0x46,0x43,0x49,0x07,0xf0,0x3e,0xc8,0xbe,0x66,0xaf,0x58,0x3a,0xbd,0xd8,0x00},{0x35,0xf5,0xc8,0x2c,0x0e,0x4b,0x56,0xe0,0xef,0x08,0x34,0x38,0x57,0xe9,0xde,0xdb,0x1d,0xe1,0x28,0x05,0x01,0xed,0x62,0x3d,0xa9,0x6e,0xea,0x5b,0x95,0x09,0xe0,0x04,0x46,0xff,0xdc,0x34,0xf6,0xf7,0x63,0xb1,0x76,0xb8,0x3c,0x03,0xef,0x36,0x0f,0x82,0x1b,0x5b,0x6f,0xe2,0x86,0xd9,0x10,0x01,0xe6,0x73,0x75,0x0d,0x50,0x30,0x11,0x68},{0x27,0xb6,0x3b,0x78,0x79,0xf3,0x22,0x78,0x8f,0x0c,0x14,0x8b,0x3f,0x68,0xc2,0xab,0x9f,0x9f,0x05,0x70,0x7e,0xee,0x4b,0x1b,0x6b,0xfc,0x04,0x72,0xca,0xf1,0x9a,0xba,0xe3,0x65,0x9d,0xdb,0x01,0x33,0xc5,0xdb,0xf6,0x87,0xe4,0x73,0x5a,0x0f,0x94,0xa9,0x2e,0xfe,0x8f,0x3e,0xd1,0x0a,0x6d,0xa1,0x21,0x2a,0x92,0x8c,0x4b,0x43,0x13,0x2f},{0xa3,0xa8,0x3b,0xb4,0x4f,0x8a,0xac,0xab,0x8a,0x4c,0x39,0x7e,0xb8,0x2f,0xb1,0x01,0x2e,0xbe,0x0e,0x7d,0x28,0x8a,0x18,0x4a,0xda,0x58,0x1a,0xfb,0x95,0x97,0xf3,0x63,0x58,0xbe,0x8c,0x30,0x13,0x9b,0xba,0x9f,0x4e,0xac,0x8d,0x95,0xf2,0x07,0xbb,0x85,0xa1,0x41,0x4c,0x33,0xe3,0x58,0x8e,0x5c,0xa1,0x05,0x45,0xab,0x5c,0x0c,0xe4,0x02,0xc3,0xa0,0xa0,0x72,0xdb,0x9a,0x9d,0xbf,0x13,0x29,0x94,0x70,0x8b,0xe4,0xe8,0xdb,0x0e,0x0b,0xd0,0xa0,0x25,0xad,0x71,0xa0,0x27,0x9c,0x1d,0x77,0xb0,0x98,0xa8,0x03},{0xe1,0x84,0xa5,0xea,0xa5,0xd8,0x1b,0x29,0xce,0xd7,0xa3,0x72,0xa7,0xc9,0xa5,0xea,0xf1,0x02,0xf3,0x0c,0xb0,0x65,0x12,0xbc,0xa4,0xf2,0x5d,0x69,0x00,0xa4,0x7f,0x5a,0x52,0x09,0xb6,0x7b,0x30,0xf2,0x99,0x03,0x39,0x9d,0xee,0x6f,0xb5,0xf7,0x9e,0x7a,0x97,0x8b,0x81,0x03,0x8c,0xdd,0x35,0xfc,0x1f,0x0a,0xc6,0xa4,0x60,0x7b,0xc8,0x0a,0xc3,0xa0,0xa0,0x72,0xdb,0x9a,0x9d,0xbf,0x13,0x29,0x94,0x70,0x8b,0xe4,0xe8,0xdb,0x0e,0x0b,0xd0,0xa0,0x25,0xad,0x71,0xa0,0x27,0x9c,0x1d,0x77,0xb0,0x98,0xa8,0x03}},
|
||||
{{0x67,0xe9,0x62,0x76,0x3a,0x90,0x9b,0x6b,0x19,0x1d,0x65,0xb2,0x2a,0x2f,0xf7,0x50,0xaa,0x54,0xa5,0xbb,0x53,0xb5,0xf9,0xee,0x0c,0x04,0x3a,0x3c,0x29,0x4b,0x66,0x3e,0x7b,0xb6,0xaa,0xd2,0x10,0x89,0xcc,0x89,0x2c,0x47,0xbe,0x23,0xd6,0x52,0x81,0x5d,0xc8,0xbc,0x49,0xd6,0x6a,0xcd,0x62,0x99,0x30,0xff,0x16,0xa5,0x50,0x44,0xd8,0x7a},{0xd6,0xcd,0xfe,0xd4,0x44,0x4a,0x9e,0x90,0x44,0x73,0x8a,0xff,0xbb,0x82,0x08,0xb6,0x7f,0xf2,0x87,0xcb,0xa5,0x0b,0x56,0xd3,0x9e,0x91,0xb8,0x52,0x6b,0x25,0xa6,0x5d,0x50,0xaf,0x9b,0xd5,0xfb,0x9f,0x7e,0x2d,0x57,0xdf,0x30,0x78,0x8d,0x1a,0xc3,0xac,0x9c,0x5a,0xbf,0xab,0x5a,0x0d,0xc9,0xb6,0x4b,0x18,0xd4,0xe7,0x55,0x40,0xde,0x7e},{0xc2,0xa9,0x7e,0x5c,0x26,0xf4,0x7d,0xce,0x9e,0x73,0xae,0x50,0xde,0xe7,0xa6,0xf9,0x8b,0x57,0xf9,0x7a,0x4c,0x38,0x82,0xf6,0x30,0x80,0x12,0xf7,0xf6,0x66,0x80,0x46,0x4d,0x41,0x53,0x63,0xd9,0x65,0x90,0xe7,0xee,0x24,0x07,0xb0,0x4f,0xeb,0x3e,0x8e,0x83,0x21,0xa3,0x40,0x03,0xc0,0x64,0x52,0xc6,0xb2,0x12,0x9d,0x8d,0x86,0xdd,0x19},{0xe2,0xd5,0x49,0x5e,0x2a,0x6e,0x4e,0xd9,0x31,0x26,0x53,0x13,0x98,0x5e,0x2f,0x23,0xea,0xa0,0x30,0xee,0xef,0x62,0x2b,0xdc,0x93,0x65,0x90,0xad,0x9a,0xf1,0x74,0x12,0xf5,0x24,0x33,0xcc,0xc3,0xda,0x42,0x54,0xa6,0x6c,0x86,0x99,0xb9,0xb5,0xf7,0x07,0x90,0xd8,0x85,0x7f,0x69,0xfb,0x19,0x2a,0x2c,0xc0,0x11,0x81,0x64,0x37,0x38,0x07},{0xc7,0xb3,0xf5,0xe4,0x4b,0x55,0xcf,0xd8,0x2b,0x72,0xde,0x62,0xfc,0x66,0xea,0x82,0xee,0x2e,0xe5,0x4f,0x66,0xba,0x19,0x63,0x01,0x0b,0x2d,0x89,0xb4,0xaa,0x76,0xb3,0x7e,0xc5,0xbe,0xdd,0x57,0x90,0x5e,0xff,0x5b,0x9a,0x71,0xe1,0x47,0xf9,0xec,0xe5,0xf0,0x19,0x89,0x17,0x65,0x3e,0x56,0x4a,0x98,0xb2,0x3c,0x3b,0xf0,0x14,0x13,0x1b},{0xc0,0x72,0x26,0x96,0x6b,0xf5,0x50,0xa1,0x65,0xcd,0xfe,0x92,0xa5,0x5a,0xb3,0x56,0x27,0x5b,0x2f,0x4a,0x8f,0x67,0xaa,0xf4,0xa1,0x6e,0x3c,0x66,0xcc,0xb7,0x71,0x70,0xff,0x70,0x1f,0x9e,0x09,0xae,0x31,0xcb,0x2a,0xd5,0x8a,0x38,0xa9,0xaf,0xbc,0x94,0xa2,0xa8,0xe9,0x77,0x1c,0xc3,0xfa,0xd1,0x45,0xd2,0xe2,0xff,0x7d,0xf2,0x44,0x00,0xa0,0xc3,0xc1,0xdd,0xa0,0x4c,0xfb,0xed,0x1a,0xbd,0x0c,0x05,0x3b,0xa9,0xc8,0x98,0xb0,0x7d,0x6a,0x77,0xcb,0x08,0x70,0x64,0x31,0x9d,0x9c,0x7b,0x40,0x9e,0xbb,0xf4},{0xbc,0x88,0x9d,0x36,0xae,0xbc,0x92,0x47,0x63,0x85,0x41,0xe3,0x1e,0x1c,0x39,0xf5,0xd3,0xc2,0x0a,0x7d,0x18,0x7a,0x8f,0xd3,0x0c,0x37,0x50,0x28,0x35,0x93,0x77,0x4b,0xcb,0xba,0x35,0x4e,0x94,0x48,0xe4,0x0c,0xa7,0x36,0x4f,0x74,0x2b,0xf9,0xb5,0xb5,0xeb,0x91,0x50,0x3c,0x67,0x9b,0x4d,0x25,0xd4,0x0e,0x0d,0xb9,0x5b,0x77,0xf3,0x0e,0xa0,0xc3,0xc1,0xdd,0xa0,0x4c,0xfb,0xed,0x1a,0xbd,0x0c,0x05,0x3b,0xa9,0xc8,0x98,0xb0,0x7d,0x6a,0x77,0xcb,0x08,0x70,0x64,0x31,0x9d,0x9c,0x7b,0x40,0x9e,0xbb,0xf4}},
|
||||
{{0x44,0xdd,0x62,0x9e,0x0f,0xee,0x20,0x11,0x37,0xfc,0xd0,0x5c,0xe4,0xe1,0x0a,0xb8,0xc2,0xe0,0x9c,0x2c,0x3e,0x1b,0x31,0x1c,0xdb,0xa3,0x84,0x9a,0xb7,0x4e,0x40,0x74,0x21,0xfd,0xfc,0x65,0xbd,0x38,0x8a,0x55,0x6f,0x1e,0xc3,0x14,0xfc,0x66,0x04,0x7b,0xc4,0x61,0xb0,0xcb,0xfa,0xdd,0x50,0x45,0x4b,0x2e,0xf0,0x6d,0x0f,0x26,0x6d,0xbf},{0xe6,0xbc,0x35,0x73,0xb3,0x11,0x38,0xc6,0x31,0x82,0x96,0x80,0x1d,0xa9,0xd9,0x17,0x85,0x4e,0xad,0x0f,0x5c,0xb7,0xe8,0x78,0x62,0x2f,0x3c,0x10,0x0e,0xdc,0xf2,0x7e,0xf5,0x02,0x6d,0x1a,0x50,0xc2,0x50,0x7d,0x0d,0x14,0x77,0x77,0xfc,0xbe,0x23,0x02,0x81,0x0a,0xdc,0xa3,0x16,0xfd,0xab,0xb9,0x7c,0xb6,0x7e,0x8a,0xde,0x1f,0x22,0xeb},{0xab,0xf3,0xea,0x63,0xc0,0x25,0xa2,0xc7,0x6a,0xfe,0x91,0x4a,0x0a,0x91,0xdd,0x6d,0x6f,0x8c,0xf9,0xa8,0x1c,0x9f,0xb5,0xe5,0xd2,0xac,0xe6,0x51,0x9a,0xd3,0x87,0x17,0x82,0x12,0x0a,0x58,0x99,0x7f,0x81,0x2d,0x8d,0x27,0x2d,0x1b,0xb0,0x02,0x7e,0x0d,0xd6,0x18,0x89,0x5e,0x0c,0x2b,0x57,0xa6,0x56,0x35,0xff,0x71,0x4e,0xb0,0x49,0x38},{0x36,0xdf,0x1d,0x1c,0xf6,0xa7,0x4d,0x87,0x7e,0x2c,0x3f,0xb4,0xda,0xd7,0x80,0x71,0x0b,0xf3,0x2a,0x47,0x20,0xe6,0x9a,0x3d,0x17,0x9a,0x97,0xc9,0x4e,0x53,0xa6,0xe2,0x23,0xea,0x94,0x4d,0xf9,0xeb,0x2c,0x03,0x2c,0x88,0xa2,0xe6,0xc5,0x94,0xa5,0x6f,0xc3,0x98,0xa9,0x8b,0xa7,0x41,0x7d,0xd3,0x82,0x01,0x13,0xb6,0x0f,0x39,0x1e,0xd2},{0x08,0x28,0xc3,0x1c,0xec,0x21,0x3a,0xb4,0x4c,0xb1,0xfa,0xb9,0x0c,0xfe,0xc2,0x50,0xc5,0x99,0x62,0xa0,0x11,0x74,0xcf,0x05,0x1e,0x2b,0xdf,0x6d,0x22,0x8e,0x6e,0x55,0x19,0x21,0x9c,0xa1,0x98,0x56,0x45,0x90,0x40,0x3a,0x8e,0xad,0x76,0x4d,0xd3,0x95,0x27,0x67,0x4e,0x02,0x16,0xc3,0xfe,0x5a,0x79,0x4e,0x2d,0x6f,0xd0,0xe4,0x4f,0x62},{0x40,0x14,0xe1,0x88,0x3d,0xcc,0x51,0xcb,0x98,0x86,0x06,0x4d,0xe4,0x52,0x71,0xe2,0x2e,0x2b,0x80,0xfd,0x81,0x65,0xaf,0x93,0x31,0x87,0xe0,0xff,0x31,0xab,0xff,0x53,0x0e,0x2d,0xb1,0x47,0xe6,0x44,0xb7,0x29,0xab,0x0f,0x51,0x3a,0x53,0x84,0x36,0x58,0x8c,0x5f,0x7b,0x65,0x6a,0xb7,0x6f,0xdc,0xad,0xc1,0xa3,0xe4,0x21,0xfc,0x22,0x0e,0xc1,0x10,0xd1,0x7d,0x9f,0xd3,0x1e,0x33,0xb4,0xca,0xb9,0xff,0xd8,0x27,0xb8,0xca,0xde,0x49,0x6f,0xdc,0xf0,0xe8,0x70,0x36,0xdb,0x90,0x00,0x07,0x9e,0x77,0x39,0xfe},{0xc9,0x93,0x4b,0xe6,0x47,0x7e,0x1d,0x86,0x15,0x46,0xe8,0x27,0xf5,0x84,0x67,0x4e,0x42,0xe3,0x2b,0x8a,0x4e,0x90,0x7b,0x87,0xcc,0xdf,0xaa,0x04,0x06,0x05,0xe6,0x72,0xff,0x6f,0x44,0x1b,0x08,0xad,0x79,0x3e,0xb7,0xdd,0xd7,0x2c,0x73,0xf0,0xf0,0xc4,0x6e,0xb7,0x37,0xe1,0x02,0xf5,0x42,0xe7,0xef,0xa1,0xdd,0x50,0x9a,0xc5,0x8d,0x00,0xc1,0x10,0xd1,0x7d,0x9f,0xd3,0x1e,0x33,0xb4,0xca,0xb9,0xff,0xd8,0x27,0xb8,0xca,0xde,0x49,0x6f,0xdc,0xf0,0xe8,0x70,0x36,0xdb,0x90,0x00,0x07,0x9e,0x77,0x39,0xfe}},
|
||||
{{0x3e,0x0c,0x21,0xc4,0x3d,0x64,0x61,0xc1,0x9d,0xa1,0x83,0x10,0x74,0x1d,0x56,0x12,0xaf,0x29,0x5c,0x6c,0x12,0x48,0x0a,0xc7,0xe5,0x12,0xb6,0x42,0x6b,0x54,0xf4,0x42,0x0c,0x43,0x42,0x2e,0x78,0xc2,0xe7,0x26,0x09,0x41,0x4a,0x2f,0xa1,0xb0,0x1f,0xcd,0x63,0x76,0x1e,0xa1,0x6f,0xf6,0xe2,0xc2,0x08,0x89,0x0d,0x28,0xbf,0x1b,0x56,0x5b},{0x3e,0x2e,0xf2,0xcc,0x81,0xca,0xa7,0x5d,0x01,0xd2,0x82,0xfd,0x45,0xee,0xc0,0xf5,0x49,0x3b,0xe2,0xa4,0x2a,0x4d,0x5f,0x40,0x0d,0xbc,0xb9,0x3d,0x6e,0xda,0xe2,0x86,0xe1,0x23,0x8b,0x5f,0x0d,0xa2,0x35,0x15,0x1d,0x22,0x23,0xa5,0x69,0x56,0x34,0x78,0xb3,0xb3,0x55,0xef,0x63,0x8a,0x17,0x63,0xda,0xf0,0x64,0x99,0x8a,0x8a,0xba,0xd6},{0x68,0x79,0x36,0xa7,0x6b,0xe3,0x76,0x1c,0xe3,0x38,0x0b,0xa3,0x91,0xb6,0xb0,0x82,0x37,0xfa,0x52,0x74,0xf1,0xb5,0xd5,0xd9,0x07,0x06,0x9e,0xda,0x87,0x6b,0x0f,0x24,0x4f,0xbe,0xc9,0xff,0x03,0x41,0xaf,0x77,0x68,0xed,0xe7,0x71,0xba,0x2d,0xde,0x27,0xa1,0xbf,0xa8,0xa7,0x30,0x7c,0xcb,0x79,0x72,0x89,0x1a,0xdc,0xc1,0xe4,0xb2,0x9d},{0x94,0xa3,0x11,0xf4,0x44,0x80,0xd0,0xa3,0x47,0x93,0x36,0xe2,0xbd,0x04,0xe4,0x74,0x3d,0x00,0x60,0xad,0xd0,0x2d,0x86,0x66,0xa1,0x72,0x1a,0xb9,0x1c,0x14,0xa2,0x9b,0x4b,0x04,0x7d,0x5b,0xcd,0xf8,0x01,0x33,0xde,0x34,0x10,0x29,0xc4,0x72,0x56,0xff,0x11,0xcd,0xd8,0x61,0x2c,0xb6,0xb7,0xf4,0x24,0x8b,0x44,0xb4,0xe7,0x34,0x50,0xb8},{0x72,0xf6,0xd4,0xa3,0x24,0xf9,0xef,0xf4,0x55,0x8d,0x3c,0x07,0xca,0x10,0xdd,0x54,0x87,0x13,0x32,0x78,0x5c,0x64,0x10,0x08,0x62,0x7e,0xf4,0x34,0x0f,0x1c,0xcd,0xcc,0x3b,0x42,0xfe,0x60,0x41,0x70,0x2c,0x6b,0xd4,0x6c,0xf7,0xb8,0x24,0xf6,0xd7,0x07,0xb3,0x46,0xb0,0x7d,0x14,0x24,0x9b,0x72,0x79,0xf4,0x23,0x2a,0xec,0x02,0xe7,0x69},{0xe5,0xbe,0x84,0xc3,0x92,0x47,0x15,0xd3,0xac,0x06,0x44,0x72,0x41,0xeb,0xb6,0x5a,0x17,0x06,0x90,0xd9,0x55,0x3d,0xe4,0x87,0x7d,0x5a,0x11,0x9f,0x02,0x6d,0xd3,0x4e,0x71,0xd1,0x5e,0x16,0x9f,0xb2,0xc0,0x7f,0xcb,0x78,0x8b,0x89,0x11,0xae,0x43,0xe8,0x85,0xb7,0xf9,0xc8,0x48,0x5a,0xb2,0x96,0xaf,0x8f,0xab,0x71,0x84,0x9d,0x40,0x09,0x30,0xd4,0x32,0x6e,0xa2,0x77,0x97,0x71,0x37,0xce,0x22,0x6b,0xca,0xc9,0x79,0xef,0xc0,0xb2,0xb4,0x3d,0x30,0xbf,0x77,0xe9,0xc3,0x8d,0xec,0x15,0x04,0x08,0xfa,0x15},{0x4b,0xf3,0x7f,0xb2,0x78,0x75,0x45,0xd4,0xce,0x5e,0x3d,0xaf,0x92,0x63,0x3d,0x90,0xc0,0xa7,0x23,0x62,0x7f,0x37,0x58,0x8d,0x12,0xe0,0xb8,0x6c,0x46,0x38,0xaa,0xf7,0xe1,0x03,0x9e,0x1f,0x31,0xf9,0x5a,0xa4,0x59,0x0d,0xec,0xc5,0x1f,0x17,0x88,0x25,0xcc,0xed,0x69,0x2b,0x91,0x73,0x6a,0x3f,0xcb,0xe5,0x9c,0x1e,0x26,0x3e,0xec,0x0b,0x30,0xd4,0x32,0x6e,0xa2,0x77,0x97,0x71,0x37,0xce,0x22,0x6b,0xca,0xc9,0x79,0xef,0xc0,0xb2,0xb4,0x3d,0x30,0xbf,0x77,0xe9,0xc3,0x8d,0xec,0x15,0x04,0x08,0xfa,0x15}},
|
||||
{{0xc5,0x1d,0xcd,0x70,0xb2,0x9e,0x53,0x29,0x05,0x78,0x83,0x5d,0x56,0x30,0x89,0xee,0x02,0xd7,0xac,0x57,0x0a,0xd2,0xa0,0x9c,0x96,0x0c,0xbf,0xf2,0x30,0xbf,0x1a,0x2b,0xee,0x0e,0x9f,0x1e,0x1c,0x65,0x7d,0xb5,0x48,0xad,0x6f,0x51,0xa0,0x91,0x61,0xe4,0xe6,0x83,0x9f,0x58,0x7c,0x76,0x2b,0x52,0x94,0x87,0x3c,0x8d,0x36,0x4c,0x37,0x3c},{0x59,0x3b,0x0d,0x38,0xab,0x93,0xca,0xfb,0x67,0x44,0x30,0x96,0xec,0xbd,0x00,0x1d,0x93,0xd0,0xb3,0x3d,0x3c,0xd4,0x4e,0x3d,0xd8,0x29,0x93,0xb2,0xb3,0x77,0xfc,0x57,0x31,0x20,0xe3,0x90,0x0d,0xf4,0x91,0x2f,0x8b,0x43,0xce,0xfe,0x99,0x03,0x03,0xa2,0x90,0x8d,0xcf,0xa8,0xc0,0x21,0x00,0xca,0xcc,0xcb,0x4b,0x2f,0xa5,0x39,0xa8,0x0b},{0xca,0xf6,0xf9,0xbb,0x53,0xcb,0x97,0x76,0xb6,0x9c,0x2c,0x18,0x21,0x43,0x13,0x48,0x13,0xc9,0x0e,0xeb,0x40,0xea,0xce,0x1f,0x3a,0xe9,0xd2,0x9e,0x29,0xdb,0xe2,0x79,0xe2,0x1a,0x9f,0x84,0x9d,0xe4,0x55,0x82,0x17,0xeb,0x87,0xf6,0xc3,0xef,0xcd,0x54,0x14,0xee,0xc8,0x5b,0xd7,0x67,0x05,0xe2,0x34,0xa2,0x7e,0x81,0x83,0x21,0x7a,0x02},{0xc5,0x03,0xd9,0x75,0xdf,0x17,0x15,0xe3,0x5b,0x7b,0x4f,0x66,0x9c,0x15,0x4e,0x01,0xdf,0x3d,0x16,0xb6,0x52,0xcc,0xcf,0x28,0x40,0xdb,0x20,0xee,0x8b,0x69,0xb1,0x2b,0xc0,0x6e,0xe4,0xd2,0xf5,0xd1,0x49,0x3f,0xf3,0x0a,0x12,0xcd,0x13,0xbd,0x9d,0x3d,0x5b,0x28,0x5c,0xb0,0x0d,0x0e,0xb6,0xed,0xec,0x65,0xeb,0x25,0x28,0x2e,0x65,0x2f},{0xed,0xa7,0x05,0xc1,0xa6,0x81,0xf2,0x7a,0x69,0x68,0x17,0x8e,0xf7,0xc9,0x14,0x80,0x9f,0x81,0xfe,0x16,0xfd,0x81,0x93,0xb4,0x0b,0x05,0x5b,0x4e,0xef,0x6e,0x7a,0x67,0x9d,0x99,0x4c,0x17,0xcd,0x1c,0x16,0xfd,0x31,0x35,0xd5,0x3e,0xa3,0x00,0xbf,0xbe,0xda,0xd6,0xe2,0x37,0x9b,0x13,0x1b,0xca,0x29,0x90,0x4b,0xf2,0x09,0x57,0x2f,0xe9},{0xd7,0xba,0x23,0xd3,0xa0,0x6e,0x14,0x6a,0xf0,0x77,0xb7,0xe6,0xe3,0xc9,0x3b,0x38,0xbb,0xe7,0xbe,0x54,0x75,0xf8,0xb7,0x42,0x29,0xe2,0x83,0xde,0x20,0x22,0x41,0xcf,0x5f,0x6f,0x80,0x60,0xf3,0x44,0x04,0x21,0xd5,0x03,0x68,0x42,0xde,0x81,0xea,0xe8,0x7e,0x5b,0x80,0x0f,0x1b,0x2d,0x06,0xc7,0xce,0xe9,0x46,0xc7,0xf7,0xb3,0xa2,0x02,0x21,0xb5,0x4d,0xc2,0x36,0xea,0xe6,0x7b,0xb3,0x61,0xe6,0x18,0x40,0x5b,0xce,0x5b,0xc2,0xee,0xa5,0xde,0xe9,0xe6,0xe0,0xa8,0x58,0x58,0x03,0x34,0x26,0x27,0x65,0x2a},{0xfa,0x43,0xa6,0xc4,0x32,0xa1,0x2f,0xb6,0x37,0x05,0xf4,0xa4,0xa7,0x36,0xdd,0x1c,0x45,0x10,0x95,0x83,0x67,0x89,0x79,0x18,0x34,0xad,0xe7,0x57,0x7f,0x0d,0x48,0x9b,0x14,0xdf,0x5f,0xc8,0xd7,0x0f,0x78,0x47,0x88,0x20,0xff,0x7f,0xb1,0x21,0x27,0x14,0x58,0x32,0x12,0xfb,0x97,0xe0,0x81,0x0e,0x92,0xf4,0x5c,0x0e,0x44,0x48,0x4e,0x01,0x21,0xb5,0x4d,0xc2,0x36,0xea,0xe6,0x7b,0xb3,0x61,0xe6,0x18,0x40,0x5b,0xce,0x5b,0xc2,0xee,0xa5,0xde,0xe9,0xe6,0xe0,0xa8,0x58,0x58,0x03,0x34,0x26,0x27,0x65,0x2a}},
|
||||
{{0x1e,0x89,0x12,0xe8,0xab,0xca,0xeb,0x96,0x78,0x43,0x89,0x79,0x26,0x61,0x86,0x2e,0x37,0xd7,0x94,0xb5,0xb9,0xf7,0xc9,0xe7,0x04,0x6c,0x96,0x1c,0x54,0x0d,0xb0,0x6c,0xd3,0x68,0x9b,0x53,0xa7,0x56,0x34,0x1b,0x65,0xff,0xf9,0xee,0xf1,0xc6,0xfd,0x7e,0xa8,0x42,0x59,0x60,0x06,0x5f,0xc2,0x89,0x8b,0xfc,0xf8,0x6c,0x9a,0x0d,0xb1,0x36},{0x52,0x3d,0x83,0x25,0x0f,0x57,0x81,0x76,0x7b,0x21,0xf7,0x96,0xd6,0x1f,0xfe,0xd7,0x7c,0xc1,0x32,0xb5,0xbc,0x05,0x46,0xdb,0x6f,0x25,0xd8,0x7a,0x68,0xe2,0x01,0x81,0xf8,0x9a,0xc5,0x29,0x78,0x1c,0x01,0xc5,0x4d,0x61,0x4e,0x75,0xdf,0x9f,0xc3,0x22,0x96,0x7c,0xf9,0xa7,0xed,0x41,0x6f,0x64,0xfd,0xd4,0x61,0x58,0x0d,0x49,0xc9,0xa4},{0x4a,0xf7,0xda,0xef,0xe0,0x3b,0x33,0x19,0x79,0x02,0x7a,0xbb,0xd3,0x53,0xf4,0x8c,0x8a,0x16,0xfb,0xbd,0x35,0xd9,0x70,0xb2,0x0a,0x06,0x05,0x14,0xd0,0x9e,0xf6,0x13,0x44,0xbb,0xb7,0x93,0x86,0x1b,0x3c,0xb0,0x54,0xa7,0x48,0xc2,0xa7,0x10,0xda,0x65,0xb2,0xdb,0x0f,0x85,0x23,0x57,0x77,0x44,0x23,0x20,0x6d,0x2e,0xde,0x20,0x01,0xed},{0x9c,0xb8,0x68,0xeb,0xbb,0x8b,0xaf,0x81,0x9c,0x2f,0x90,0x4c,0xc2,0x62,0x17,0xfc,0xf2,0xa5,0xab,0x4c,0x2e,0x69,0xcb,0x82,0x5f,0x4c,0x3c,0x82,0xcd,0x6a,0xcb,0x15,0xa2,0xfc,0x50,0x54,0x5e,0x2e,0x83,0x52,0x48,0x29,0x51,0xcc,0x50,0xaa,0x27,0xa3,0xf3,0x71,0xdb,0x2c,0x1c,0xa9,0x8a,0xa5,0x95,0xab,0x3e,0x6f,0xcd,0xba,0x22,0x7c},{0xf7,0x5d,0xb5,0x20,0x65,0xfe,0xa9,0xe7,0x1f,0x8e,0xd6,0xc0,0xf2,0x3f,0x1b,0x8c,0x7a,0x02,0x54,0xd8,0xa7,0x0e,0x6f,0x68,0x94,0x81,0xff,0x30,0x0e,0x6d,0x1a,0x96,0x1b,0x86,0x07,0xaa,0xbf,0x37,0xc5,0x5e,0x26,0xa2,0xdf,0x0b,0xd0,0x7f,0x94,0x35,0x30,0xa4,0x9e,0x47,0xaf,0xad,0x9c,0xc9,0x02,0x21,0x55,0x94,0x04,0x13,0xff,0x64},{0x9c,0x8d,0x18,0x63,0x83,0xad,0x01,0xcc,0xbb,0xe6,0x00,0xda,0x15,0xce,0xc6,0x6e,0x7a,0x37,0x6a,0x81,0x44,0xb3,0xfc,0xb7,0xcd,0x05,0xee,0x4a,0x6f,0x29,0xe4,0x79,0x63,0x52,0x7e,0x14,0xc9,0x14,0x77,0xa8,0x19,0x94,0x03,0xc6,0x51,0x57,0xf1,0xcc,0x11,0x29,0xde,0x86,0x08,0xfe,0x41,0x02,0x71,0xb7,0xbf,0xd7,0xe7,0x83,0x3e,0x0c,0x9a,0x59,0x7e,0xe8,0x61,0x36,0x56,0x9a,0xbf,0x64,0xfd,0xf3,0xb7,0xb9,0x2f,0x9e,0x56,0x1f,0x57,0x45,0x2e,0x19,0x0f,0x6f,0x70,0x01,0xc2,0x48,0x05,0x23,0x9b,0x2f},{0xb5,0x4e,0xe7,0xcc,0x7b,0x66,0x7a,0xf8,0xec,0xcd,0x1b,0x0c,0x0f,0xec,0x04,0x27,0xa0,0x61,0xfd,0x12,0x2d,0xab,0xc9,0xc5,0x8e,0xee,0x36,0xc2,0xef,0x67,0xd5,0x87,0x95,0x6c,0x12,0xb7,0x12,0x81,0x55,0xe0,0x7b,0xdb,0x8f,0x67,0xea,0x04,0x55,0x91,0x9b,0x50,0x65,0x05,0xc1,0xf1,0x0b,0x04,0x91,0x66,0x3c,0x32,0x53,0x72,0x01,0x04,0x9a,0x59,0x7e,0xe8,0x61,0x36,0x56,0x9a,0xbf,0x64,0xfd,0xf3,0xb7,0xb9,0x2f,0x9e,0x56,0x1f,0x57,0x45,0x2e,0x19,0x0f,0x6f,0x70,0x01,0xc2,0x48,0x05,0x23,0x9b,0x2f}},
|
||||
{{0xc8,0x37,0x10,0xdc,0xdb,0xfc,0x51,0x91,0xae,0x37,0xa4,0xe0,0xcf,0xbb,0xdd,0x92,0x93,0x5f,0x6b,0xd6,0x81,0xbf,0x9b,0x24,0x5e,0x0d,0xf1,0xe4,0x04,0x89,0xd1,0x1b,0xb2,0x68,0x56,0x3a,0xdc,0x59,0xd0,0x8a,0x93,0x37,0x5d,0xa5,0x40,0x5e,0xfe,0xc9,0x41,0x0b,0x8a,0x50,0xd2,0xa0,0x94,0x86,0xf7,0x46,0x3b,0x7e,0x1d,0xea,0x2b,0xa8},{0x1b,0xe2,0xe6,0x48,0x86,0xa8,0x65,0xfd,0x2b,0xae,0xc7,0x7d,0x41,0xee,0xb2,0x80,0x33,0x1c,0x0a,0xdc,0x42,0xea,0x99,0xd0,0x1f,0x6d,0xc8,0x80,0x51,0x70,0xd4,0x19,0xae,0xfc,0x66,0x16,0xa2,0x53,0x27,0x19,0x7a,0xf2,0x9a,0x25,0x0c,0x39,0x8c,0xbf,0xe7,0xa3,0x7a,0xd6,0xa3,0x43,0x62,0xd2,0x4a,0xc2,0xf1,0x96,0x7e,0xe3,0x83,0x13},{0xf5,0xb1,0x2a,0xc5,0x4d,0xcc,0xdf,0x56,0xde,0x92,0x96,0x46,0x03,0x11,0xfc,0xa0,0xbc,0xa2,0x22,0xf7,0x25,0x74,0x2a,0x1f,0x27,0x34,0x18,0xe8,0x06,0xa4,0x77,0x26,0x1a,0x51,0x5e,0xfb,0x77,0xbc,0x55,0xb1,0xf8,0xa5,0x19,0x23,0x00,0x97,0xf7,0xbb,0xe4,0xcd,0x41,0x9e,0xd9,0x5e,0x0c,0x6b,0x1b,0x8a,0xba,0x52,0x93,0xbe,0x2c,0xf3},{0xb3,0x02,0xeb,0x44,0x3c,0x05,0xae,0x9c,0x94,0xa9,0x1f,0x72,0x41,0xbc,0x81,0x66,0x5f,0x50,0xc0,0x57,0xb4,0x44,0xf0,0xe1,0x2a,0xa9,0x88,0x69,0xa6,0x1c,0x05,0x85,0xda,0xc7,0xb2,0xe1,0x8c,0x2f,0x7c,0x49,0x37,0xa2,0xf2,0x56,0xab,0x12,0x9f,0x12,0x4b,0x1b,0x73,0x75,0x3f,0x30,0x0f,0x40,0xf1,0xf9,0x1d,0xa7,0x2c,0x98,0x8c,0x91},{0xcb,0xd3,0x39,0x60,0x56,0xe3,0xbd,0x65,0x86,0x1a,0x58,0x40,0xc0,0xa4,0xc4,0x8b,0xe5,0xf7,0x49,0x0a,0xf2,0x09,0x51,0x32,0x6e,0x06,0x5a,0x27,0x19,0x78,0x2e,0x3a,0x04,0xf9,0x34,0x80,0x49,0x39,0x93,0xcd,0x89,0x67,0x7b,0xc0,0x8d,0x9d,0x8d,0x4c,0x83,0x20,0x80,0xfc,0x00,0xf2,0x8a,0x8f,0xa4,0x4d,0x8e,0x8f,0x58,0x51,0x5b,0x71},{0x71,0x3f,0x90,0x41,0xb8,0x74,0xbc,0x7a,0x85,0xf5,0xab,0xca,0x7e,0xf2,0x70,0x41,0xbc,0x36,0xb5,0xc3,0x4e,0xf1,0x2b,0x17,0x35,0x40,0xdb,0x3c,0xdb,0xd2,0xec,0x0b,0x99,0xc1,0x43,0x17,0xad,0x38,0x45,0x2d,0x07,0x31,0xd7,0xb6,0x95,0x1c,0x89,0x25,0xe4,0x89,0x97,0xd3,0xcf,0x11,0x2f,0x63,0x31,0x51,0xa2,0x18,0xfc,0x12,0x04,0x0a,0xb0,0x33,0xce,0x0b,0x57,0xc0,0x8c,0x58,0x25,0xf8,0x9b,0x50,0x22,0x1c,0x5c,0x7b,0x02,0xc7,0xed,0xfc,0x98,0x8b,0xbd,0xd2,0x4e,0xfc,0x78,0x91,0x7f,0x4c,0x99,0x24},{0xfc,0x46,0xe4,0x85,0x0c,0x52,0x14,0xf8,0x8a,0xa4,0x97,0x17,0x10,0xb2,0x93,0xef,0xa0,0x66,0x3c,0xfd,0x61,0x42,0x24,0x30,0x70,0x4b,0xfd,0x0b,0x86,0xc8,0x97,0xd7,0x04,0xc2,0xa6,0x61,0x41,0xaf,0xcc,0x1d,0x52,0xc9,0xf3,0xca,0xe1,0x90,0x7c,0xbd,0xce,0xaf,0x30,0xc4,0xb4,0x7d,0x81,0x7e,0xbd,0xe2,0x09,0x70,0x1e,0x6b,0xb9,0x03,0xb0,0x33,0xce,0x0b,0x57,0xc0,0x8c,0x58,0x25,0xf8,0x9b,0x50,0x22,0x1c,0x5c,0x7b,0x02,0xc7,0xed,0xfc,0x98,0x8b,0xbd,0xd2,0x4e,0xfc,0x78,0x91,0x7f,0x4c,0x99,0x24}},
|
||||
{{0x5f,0x01,0x6d,0xec,0x82,0x02,0x96,0x47,0x74,0xd9,0x73,0x2e,0x2e,0x17,0x00,0xb6,0xe0,0xa4,0x13,0x17,0xae,0x7f,0x85,0xcb,0xff,0xe7,0x96,0x99,0xdb,0x9f,0xad,0x21,0x60,0xd9,0x12,0xdc,0x41,0x01,0x33,0x66,0x4c,0x24,0x8b,0x25,0x17,0xd7,0x22,0x14,0x12,0x4d,0xad,0x82,0x9a,0x85,0x69,0x5e,0x35,0x10,0xe0,0xd7,0x1a,0x82,0x88,0x14},{0xab,0x5f,0x2c,0x7d,0xa2,0xe5,0x67,0x5f,0xe4,0x92,0x03,0x93,0xd7,0x13,0xa1,0xfa,0x4a,0xb7,0x18,0x4a,0x8e,0x8c,0x78,0x9a,0x0c,0x60,0x02,0xe8,0x2d,0x50,0x05,0x0f,0x92,0xee,0x9f,0x81,0xde,0x6b,0x20,0xe4,0x9b,0x17,0x2e,0x99,0x0f,0x01,0x31,0xa7,0xc5,0xc4,0x53,0x70,0xda,0x03,0xc6,0xf7,0x22,0x87,0x98,0x87,0x19,0x36,0xa6,0x49},{0x93,0xab,0x22,0xc4,0x39,0x6c,0x97,0x80,0xd2,0xe2,0x36,0xfa,0x31,0x74,0x67,0xcc,0x50,0x1b,0x95,0xbe,0x77,0xe0,0xd1,0x00,0x74,0x04,0xe1,0x4d,0xca,0x44,0x35,0x72,0x74,0x69,0x82,0x23,0x56,0x9b,0xcc,0x34,0x5a,0xcb,0xa2,0xa3,0x31,0x12,0x4a,0x84,0x4c,0xe9,0x37,0x3a,0x58,0xf8,0x79,0x65,0x4a,0x66,0x79,0x82,0xf4,0x5d,0x75,0xc3},{0x2d,0x5d,0xac,0x4f,0xb5,0x00,0x68,0x3b,0x5f,0x2e,0xdd,0xcb,0x14,0x4a,0x7f,0xad,0x12,0x45,0x91,0xd1,0x84,0xd8,0x14,0xff,0xcb,0x64,0x43,0x6d,0x65,0xe7,0x19,0x68,0x2b,0x5e,0x53,0x05,0x74,0x66,0xed,0xac,0x2f,0x5a,0x8f,0x70,0x96,0xab,0x29,0xf3,0x9a,0x59,0xa2,0xe2,0xef,0xd3,0xc9,0xd7,0x53,0xf8,0xf5,0xa3,0xd6,0xf4,0x34,0xf8},{0x1d,0x14,0xf3,0xfd,0xb0,0x66,0x20,0xff,0xfc,0x79,0x47,0xc7,0x4c,0xe9,0x45,0x67,0xf5,0x97,0x14,0xea,0x7c,0x63,0xc5,0x3f,0x0b,0x46,0xe0,0x88,0xd6,0x9b,0x67,0x71,0xba,0xa6,0x15,0x28,0x94,0x54,0x83,0x68,0x00,0x3a,0x33,0xa6,0x1a,0x05,0x6a,0x68,0x72,0x98,0x48,0x71,0xea,0x5b,0x47,0xf5,0x80,0x46,0xa9,0x57,0x84,0xec,0xad,0xfc},{0xa3,0x1d,0x87,0xd3,0x28,0x62,0xc6,0xf7,0xdb,0xfb,0xfa,0xfc,0xf3,0x27,0x5c,0x31,0xd3,0x32,0x26,0x0e,0x0f,0x41,0x49,0xec,0x05,0x16,0xf7,0xa5,0x63,0xb3,0xbc,0xe5,0x0d,0x1e,0x6f,0x97,0x4f,0x68,0x40,0xc0,0xd4,0x6c,0x4f,0x9e,0x25,0xd0,0xab,0x8d,0x2a,0xb9,0x3e,0x06,0x4d,0x9d,0x3d,0x2d,0x79,0x8d,0x93,0xdc,0xfc,0x6f,0x0b,0x04,0x48,0x7c,0x19,0x5c,0xa9,0xc8,0x44,0xe5,0xf6,0x4f,0x51,0xd8,0x72,0x63,0x41,0xda,0x62,0xac,0x78,0x73,0xb3,0x3e,0xc8,0xb2,0xf1,0x3f,0x89,0xf2,0x0e,0x95,0xdf,0xed},{0xfd,0x69,0xb1,0x9a,0xdb,0xae,0x95,0x87,0xe2,0xc6,0x8a,0x97,0x0c,0xee,0xc4,0x22,0x60,0x4e,0x96,0xa9,0x72,0xb9,0x6f,0x86,0x97,0xa8,0xdf,0x83,0xc5,0x18,0x18,0x6e,0xc9,0x43,0x30,0x7e,0x5b,0xcf,0x37,0x0f,0xc1,0xd7,0xe5,0xab,0xb1,0x31,0xe0,0x97,0xc7,0x53,0xb7,0xfd,0xd7,0xdf,0x00,0x43,0x0e,0x41,0x62,0x80,0x0b,0xe3,0xe0,0x06,0x48,0x7c,0x19,0x5c,0xa9,0xc8,0x44,0xe5,0xf6,0x4f,0x51,0xd8,0x72,0x63,0x41,0xda,0x62,0xac,0x78,0x73,0xb3,0x3e,0xc8,0xb2,0xf1,0x3f,0x89,0xf2,0x0e,0x95,0xdf,0xed}},
|
||||
{{0x98,0x29,0xf7,0x57,0xfd,0xbd,0x44,0x3f,0xd9,0x90,0x98,0x19,0x97,0xf2,0x60,0x27,0xfd,0x08,0xfc,0x8a,0xc6,0xaf,0x87,0x22,0x7f,0x74,0x4a,0x80,0xaf,0x72,0x00,0x01,0x70,0x9b,0x47,0x2a,0xd2,0x8e,0x41,0x0a,0xea,0x6a,0xdf,0xb7,0x61,0x54,0x89,0x5e,0x01,0x9f,0x76,0x64,0x29,0xee,0x8d,0x85,0x20,0xff,0x30,0x58,0xc2,0xa3,0x2a,0x56},{0xea,0x69,0x8e,0x6b,0x8e,0xdd,0x55,0x22,0x45,0x61,0xd4,0x92,0x66,0x8e,0x96,0xaf,0x7e,0x40,0x28,0x72,0xc4,0x46,0xe7,0x88,0xd4,0x6c,0x74,0xb7,0x48,0x7f,0xe8,0xe1,0x5e,0xa5,0x85,0x62,0x8f,0xd6,0xfc,0x27,0x0a,0xb2,0x4b,0x38,0x94,0x59,0x52,0x0d,0x6a,0x4d,0xe5,0x61,0xce,0x0d,0x44,0x03,0xa6,0x2a,0xc2,0xd4,0xd4,0xe2,0x71,0xe3},{0x40,0xf0,0x82,0xf0,0x8d,0xaa,0xad,0xa9,0x9f,0x9b,0x85,0x02,0xcf,0x57,0x15,0x41,0x13,0x59,0xf2,0xba,0xdd,0xbf,0x93,0xe5,0x40,0x2e,0xaf,0xdd,0x43,0x52,0xc8,0x7f,0x40,0xad,0x91,0x5b,0x58,0xd1,0xa1,0xe8,0x6f,0x77,0xc3,0x41,0x35,0x5e,0xf7,0x03,0xba,0xe4,0xed,0x2c,0x28,0x59,0xd6,0x48,0xfe,0x50,0xcc,0xf9,0x80,0xd1,0x49,0xd1},{0xd7,0xa5,0xd9,0x13,0xdf,0x7d,0xf6,0xc6,0x25,0x0f,0x52,0xc2,0x57,0x61,0x20,0xf2,0xf0,0xdb,0x47,0x49,0x56,0xaf,0x89,0x11,0xa7,0x8d,0x09,0x3a,0xfe,0x45,0x43,0xef,0x9f,0x0c,0x42,0xaf,0xa8,0xcc,0x60,0x48,0xc0,0x1c,0x7c,0xbe,0x01,0xe2,0x88,0xcc,0x6c,0x3e,0x97,0x91,0xf3,0xd9,0xb2,0xb2,0x09,0x7e,0x35,0xb1,0x78,0xb4,0x03,0xf6},{0x08,0xc4,0x1a,0x3a,0xc3,0xe3,0x26,0xbd,0x8d,0xee,0x5d,0xf0,0xba,0xb6,0x65,0xff,0x77,0xc0,0x99,0xd1,0xca,0xdc,0xf5,0x4b,0x50,0x50,0x0a,0x9e,0x13,0x33,0x76,0x86,0x9b,0x39,0x79,0x78,0x73,0x5c,0x2f,0x69,0xa9,0x9e,0x0b,0xeb,0x11,0x1e,0x12,0xaa,0xc1,0x09,0x83,0x0f,0xca,0xcb,0x95,0x10,0xde,0x85,0xe3,0x75,0x62,0x4a,0xc2,0x4c},{0x68,0x78,0x6c,0xce,0x2f,0x72,0x80,0xfe,0x83,0x88,0x63,0x37,0xa7,0xa1,0x5a,0x0b,0x84,0x8a,0xda,0x28,0x84,0xf1,0x6a,0x63,0x24,0x1c,0x72,0xda,0x84,0xee,0x1d,0xe0,0x77,0xf0,0xf6,0xce,0x7e,0x79,0x0a,0x55,0x03,0x01,0x13,0x0f,0xf7,0x6b,0x45,0xe7,0xcb,0xfd,0xb0,0x37,0x93,0x4b,0x40,0x69,0xe0,0x77,0x67,0x72,0x65,0xee,0x35,0x08,0x00,0xc0,0x07,0x10,0xd8,0x6e,0x55,0x83,0x5a,0xbc,0xfa,0x67,0x80,0x8f,0xfa,0x21,0x3e,0x56,0x53,0x5b,0xbc,0x9d,0xff,0x16,0xd9,0x57,0xcf,0x2b,0x78,0x06,0x5a,0x89},{0xdf,0x32,0x1a,0x01,0x84,0xe5,0xb8,0x2c,0x70,0x6c,0xeb,0xd1,0xf0,0xb4,0x9b,0x32,0xc8,0xd0,0x81,0xc4,0xea,0xb2,0x7c,0x32,0x1a,0x02,0x61,0xf2,0xd9,0x4d,0xe5,0x85,0xad,0xfc,0xc6,0x70,0xee,0x85,0x77,0x07,0x9b,0x5d,0x5f,0x88,0xef,0xb6,0xd8,0xdf,0x2b,0xa2,0x4d,0x90,0x11,0x2d,0x38,0x3f,0xa8,0x84,0xf0,0x76,0xdd,0x31,0xd0,0x09,0x00,0xc0,0x07,0x10,0xd8,0x6e,0x55,0x83,0x5a,0xbc,0xfa,0x67,0x80,0x8f,0xfa,0x21,0x3e,0x56,0x53,0x5b,0xbc,0x9d,0xff,0x16,0xd9,0x57,0xcf,0x2b,0x78,0x06,0x5a,0x89}},
|
||||
{{0x25,0x87,0x1e,0x6f,0xe8,0xd0,0xde,0x1d,0xd5,0xf2,0xd3,0x5b,0xff,0x9e,0x67,0x99,0x60,0xb4,0x0e,0xb7,0x98,0x1b,0x2a,0x3a,0x9c,0xec,0xc1,0xe1,0x2e,0x2b,0xc0,0x3e,0x3c,0xfb,0x64,0x91,0x72,0xc6,0x7e,0x57,0x47,0x00,0x97,0xbf,0x8e,0x0e,0xbf,0xad,0xd9,0x28,0x86,0x7c,0xfd,0x41,0x91,0xae,0x2d,0xee,0xc0,0xb2,0x32,0x7d,0x99,0x7d},{0x63,0xc1,0xf9,0x61,0x9c,0x9e,0x1a,0xd7,0xca,0xa3,0x71,0xd6,0x34,0x3d,0xa7,0x08,0x36,0x0c,0xec,0x37,0x35,0x94,0x1a,0x45,0xa9,0xfa,0xf2,0xb5,0x25,0x92,0xbf,0xd1,0x1e,0xca,0xdd,0x5a,0x23,0xad,0x9e,0x45,0xc3,0x66,0xcb,0x8f,0xda,0xa3,0xd1,0xe6,0x27,0x38,0x11,0x54,0x67,0x31,0x03,0x64,0x35,0xe0,0x68,0x0b,0x93,0xee,0x81,0x17},{0x8b,0x01,0xe9,0x99,0x54,0x54,0x73,0x15,0x0b,0xac,0x38,0x7b,0xe9,0xe3,0x17,0x4f,0x02,0x3e,0xe3,0x8e,0xda,0x41,0xa0,0x9d,0x10,0xe0,0xda,0x11,0xfe,0xec,0x2f,0x42,0xe7,0xc8,0xb3,0xde,0x2f,0x7b,0xfd,0xdf,0x7c,0x34,0x3b,0x5e,0xac,0x22,0x8c,0x99,0x3d,0xa1,0xa9,0xd9,0x81,0xb6,0x51,0xc8,0xaf,0x3e,0x75,0xed,0x45,0xcf,0xf7,0xb9},{0xaf,0xe9,0x9c,0x16,0x4a,0x8f,0x3b,0x0f,0xef,0x71,0x2f,0xaa,0x8d,0x7d,0xce,0xed,0xea,0x31,0x93,0xaf,0x2c,0x75,0xc6,0xfa,0xda,0x3e,0xa6,0xea,0x2a,0x3e,0x7b,0x72,0xb6,0xf8,0xd7,0x9a,0x88,0xcb,0x0b,0x81,0x97,0x24,0x29,0x3b,0x11,0x23,0x69,0xc2,0xff,0x98,0x39,0x25,0x99,0xae,0xe1,0x07,0x3e,0x97,0xde,0x10,0x21,0x23,0x7a,0x2d},{0xbe,0x2f,0xb9,0x4c,0x41,0x5a,0x9a,0xf6,0xfb,0xf8,0x26,0x9d,0x81,0x7f,0x39,0x91,0xaf,0x5b,0xf1,0xd7,0x93,0x0a,0xdf,0x18,0x19,0x4a,0x80,0x74,0x14,0x98,0x2b,0xf2,0x3b,0x25,0xc5,0xe8,0xfc,0x07,0x3f,0x5d,0xa1,0x39,0x27,0x4e,0x1c,0xd2,0x7a,0xfe,0x3e,0x7b,0x03,0x35,0x15,0x9e,0x35,0x2b,0xd0,0xbe,0x67,0x48,0x42,0xdd,0xa4,0xdd},{0xbd,0xcd,0xd7,0xbf,0xb1,0x0a,0xdb,0x9f,0x85,0x42,0xba,0xf4,0xc8,0xff,0xb0,0xe1,0x9a,0x18,0x6d,0x1a,0xe0,0x37,0xc1,0xa2,0xe1,0x1c,0x38,0x55,0x14,0xbf,0x64,0x67,0x84,0x47,0xb6,0x0a,0xf6,0x93,0xf1,0x10,0xab,0x09,0xf0,0x60,0x84,0xe2,0x4e,0x4b,0x5e,0xa2,0xd2,0xd1,0x19,0x22,0xd7,0xc4,0x85,0x13,0x23,0xa3,0x6a,0xb6,0x75,0x0f,0x43,0xe6,0xde,0x7b,0x67,0x2a,0x73,0x77,0x9e,0xb4,0x94,0x6c,0xc3,0x9a,0x67,0x51,0xcf,0xe9,0x47,0x46,0x0e,0x3a,0x12,0x7d,0x7c,0x66,0x73,0x6c,0xd5,0x4a,0x21,0x4d},{0x89,0x7e,0xd0,0xbf,0x2e,0x9f,0x0c,0xff,0x6e,0x56,0x25,0x9b,0x79,0x99,0x52,0x27,0xc2,0x3a,0xaa,0xf0,0x47,0x6d,0xed,0x05,0xa1,0xeb,0x9c,0x92,0x28,0x7f,0x1b,0xc8,0x1c,0x57,0x76,0xab,0x05,0xe3,0xd3,0xb7,0xa3,0xf5,0xac,0xa8,0x21,0x33,0x7c,0xb7,0xe7,0xc2,0xd0,0x25,0x6f,0xdf,0x34,0xd1,0xb0,0x34,0x41,0x46,0x30,0x9c,0x76,0x07,0x43,0xe6,0xde,0x7b,0x67,0x2a,0x73,0x77,0x9e,0xb4,0x94,0x6c,0xc3,0x9a,0x67,0x51,0xcf,0xe9,0x47,0x46,0x0e,0x3a,0x12,0x7d,0x7c,0x66,0x73,0x6c,0xd5,0x4a,0x21,0x4d}}
|
||||
};
|
||||
|
||||
/*
|
||||
static const uint8_t AES_TEST_VECTOR_0_KEY[32] = { 0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4 };
|
||||
static const uint8_t AES_TEST_VECTOR_0_IN[16] = { 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a };
|
||||
static const uint8_t AES_TEST_VECTOR_0_OUT[16] = { 0xf3,0xee,0xd1,0xbd,0xb5,0xd2,0xa0,0x3c,0x06,0x4b,0x5a,0x7e,0x3d,0xb1,0x81,0xf8 };
|
||||
|
||||
static const uint8_t AES_GMAC_VECTOR_0_KEY[32] = { 0xbb, 0x10, 0x10, 0x06, 0x4f, 0xb8, 0x35, 0x23, 0xea, 0x9d, 0xf3, 0x2b, 0xad, 0x9f, 0x1f, 0x2a, 0x4f, 0xce, 0xfc, 0x0f, 0x21, 0x07, 0xc0, 0xaa, 0xba, 0xd9, 0xb7, 0x56, 0xd8, 0x09, 0x21, 0x9d };
|
||||
static const uint8_t AES_GMAC_VECTOR_0_IV[12] = { 0x2f, 0x9a, 0xd0, 0x12, 0xad, 0xfc, 0x12, 0x73, 0x43, 0xfb, 0xe0, 0x56 };
|
||||
static const uint8_t AES_GMAC_VECTOR_0_IN[16] = { 0xdb, 0x98, 0xd9, 0x0d, 0x1b, 0x69, 0x5c, 0xdb, 0x74, 0x7a, 0x34, 0x3f, 0xbb, 0xc9, 0xf1, 0x41 };
|
||||
static const uint8_t AES_GMAC_VECTOR_0_OUT[16] = { 0xef, 0x06, 0xd5, 0x4d, 0xfd, 0x00, 0x02, 0x1d, 0x75, 0x27, 0xdf, 0xf2, 0x6f, 0xc9, 0xd4, 0x84 };
|
||||
|
||||
static const uint8_t AES_GMAC_VECTOR_1_KEY[32] = { 0x83,0xC0,0x93,0xB5,0x8D,0xE7,0xFF,0xE1,0xC0,0xDA,0x92,0x6A,0xC4,0x3F,0xB3,0x60,0x9A,0xC1,0xC8,0x0F,0xEE,0x1B,0x62,0x44,0x97,0xEF,0x94,0x2E,0x2F,0x79,0xA8,0x23 };
|
||||
static const uint8_t AES_GMAC_VECTOR_1_IV[12] = { 0x7C,0xFD,0xE9,0xF9,0xE3,0x37,0x24,0xC6,0x89,0x32,0xD6,0x12 };
|
||||
static const uint8_t AES_GMAC_VECTOR_1_IN[81] = { 0x84,0xC5,0xD5,0x13,0xD2,0xAA,0xF6,0xE5,0xBB,0xD2,0x72,0x77,0x88,0xE5,0x23,0x00,0x89,0x32,0xD6,0x12,0x7C,0xFD,0xE9,0xF9,0xE3,0x37,0x24,0xC6,0x08,0x00,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x00,0x05 };
|
||||
static const uint8_t AES_GMAC_VECTOR_1_OUT[16] = { 0x6E,0xE1,0x60,0xE8,0xFA,0xEC,0xA4,0xB3,0x6C,0x86,0xB2,0x34,0x92,0x0C,0xA9,0x75 };
|
||||
|
||||
static const uint8_t AES_GMAC_VECTOR_2_KEY[32] = { 0x63,0x2f,0xd9,0x48,0xcf,0x70,0xe2,0xee,0x70,0x63,0xe8,0x7a,0x4a,0x2a,0x39,0x9b,0x67,0x08,0x64,0x03,0x68,0x9d,0xbc,0x60,0xea,0x68,0x4a,0x7a,0x83,0x37,0x00,0xfe };
|
||||
static const uint8_t AES_GMAC_VECTOR_2_IV[12] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b };
|
||||
static const uint8_t AES_GMAC_VECTOR_2_IN[541] = { 0xc8,0x36,0x38,0xe8,0x53,0xc8,0x86,0xa3,0xe3,0xad,0x9e,0x2a,0x91,0x47,0xb9,0x51,0xad,0xf7,0x78,0x89,0x9a,0xeb,0x80,0x41,0x67,0xa9,0x16,0xc4,0x93,0xcc,0x77,0x3d,0x8c,0xcf,0x4d,0xb5,0x0b,0xda,0xfd,0xc2,0x8c,0x83,0x5d,0x66,0x43,0x74,0x21,0xbd,0xc4,0xab,0x41,0xd8,0x40,0x53,0x34,0xe8,0x05,0xcb,0x89,0x45,0x09,0xb0,0xa4,0xa6,0x04,0x95,0x19,0x2c,0xab,0x94,0xe1,0x8d,0x7b,0x59,0x8b,0xb9,0x31,0xae,0x3c,0x25,0xd3,0x23,0xab,0x8f,0x95,0xa3,0x8b,0xa5,0xc1,0x66,0x8b,0x57,0xe4,0x88,0x70,0xc9,0xe0,0xa1,0x16,0x39,0xf8,0x12,0xb3,0xe5,0x95,0x38,0x3a,0x01,0x1d,0xcc,0xc0,0xc3,0xa9,0x1c,0x72,0xa7,0x46,0x79,0x51,0x05,0xb2,0x85,0x5a,0x97,0x16,0x97,0xa6,0x85,0xa4,0xf2,0x0b,0x3c,0x90,0x52,0xa3,0xe0,0xbe,0xad,0x06,0x1b,0x8e,0x04,0x22,0xeb,0x3a,0x48,0xb9,0x84,0x24,0x0b,0x24,0x42,0xd9,0xed,0x6b,0x5c,0xc1,0xb6,0x2e,0xa5,0xc0,0x07,0xfe,0x3e,0xbc,0x9a,0x92,0x26,0xb5,0xa6,0x5f,0x09,0x13,0x85,0x5a,0xcf,0x61,0x56,0x65,0x0f,0x4c,0x64,0x79,0xfa,0x0a,0xcf,0xc0,0x95,0x8d,0x4d,0xc6,0xbe,0xee,0xb3,0x67,0xd8,0xa7,0x40,0x90,0x61,0xe3,0xba,0xcb,0x18,0xe0,0x61,0x7b,0x33,0x86,0xf7,0xef,0x64,0xe5,0x36,0xf0,0x9c,0xb6,0x34,0xb1,0xe1,0x2a,0xd8,0xd8,0x5e,0x6b,0x61,0x92,0xa0,0x8e,0x04,0x7b,0xbf,0xa5,0x84,0x39,0x3a,0xe0,0x27,0xc7,0xb0,0x83,0x88,0x4f,0x3e,0x49,0x14,0xaa,0x34,0xde,0xb4,0xbb,0x4c,0xe4,0xbf,0xae,0x9a,0xf9,0x88,0x7a,0x1f,0x18,0xa0,0x8c,0x60,0xc0,0x5c,0x46,0xa1,0xd1,0x36,0x99,0x60,0x9b,0x73,0xa2,0x9a,0x0b,0x8d,0x6e,0x2f,0xe1,0x58,0x7a,0x39,0x71,0xed,0xfc,0x34,0xe4,0x98,0x57,0x7e,0x86,0xf1,0xe5,0x00,0x7d,0x1b,0x6a,0xfa,0xf8,0x6e,0x7b,0x12,0x44,0x04,0x60,0x02,0x81,0x12,0x09,0x00,0xb4,0x35,0x9e,0x03,0x73,0x79,0x9b,0x13,0xc5,0xd7,0x0e,0xce,0x49,0x87,0x48,0x1a,0x67,0x89,0x93,0xef,0xd1,0xdf,0x2d,0x48,0x6d,0x30,0xd5,0xec,0x49,0xfe,0x15,0x1b,0xa6,0x2b,0x6c,0x08,0x8e,0x39,0x73,0x68,0x87,0xa7,0x43,0x28,0x16,0x77,0x86,0xd1,0xcb,0x13,0xe4,0xd3,0xda,0x63,0xcd,0x3a,0x2a,0x35,0xd5,0xfa,0x36,0x67,0xc8,0x4c,0x6b,0xa1,0x8a,0xaf,0x7b,0x4c,0x43,0xb0,0x2f,0x4a,0xcc,0xc0,0x11,0xc6,0x30,0x8e,0xa3,0xd2,0x4a,0x1b,0x2a,0x4f,0xec,0x97,0x83,0xa6,0x4c,0xee,0x51,0xaf,0x06,0x0a,0x1d,0x80,0xd9,0xcf,0xb7,0x69,0x23,0x15,0x3a,0x26,0x04,0x34,0x33,0x76,0x30,0x9f,0xfb,0x56,0xb4,0x26,0xee,0xfa,0x54,0x6c,0x18,0xf9,0xd5,0x32,0x5d,0x03,0xcb,0x2c,0x20,0x30,0x0c,0xa0,0xbb,0xde,0x01,0x77,0x65,0xb0,0x18,0x30,0xd2,0x55,0x9f,0x9b,0xcf,0xb8,0x9b,0xb4,0xbc,0x0b,0x49,0x52,0x53,0x30,0x48,0xa5,0x12,0xe5,0x3b,0x47,0x84,0xff,0xf1,0x53,0x5d,0x5c,0x04,0x70,0x63,0x91,0xc3,0xc0,0xf0,0xea,0xcb,0x44,0x4f,0x8c,0x85,0x42,0x6a,0xc7,0xfa,0xc7,0xb5,0x30,0x03,0x12,0x65,0xca,0xba,0x4f,0x67,0xbb,0xef,0xb6,0xc6,0x3f,0x19,0xe2,0xb5,0x4b,0x8c,0xfc,0x9e,0x18,0xb0,0x33,0x89,0x6e,0xde,0x61,0x0a,0xe3,0x5e,0xa3,0x5d,0x2e,0x80,0x3e,0x53,0x67,0xfb,0x7b,0x7a,0xbf,0xd5,0xf4,0x47 };
|
||||
static const uint8_t AES_GMAC_VECTOR_2_OUT[16] = { 0x67,0x39,0x4f,0x00,0x04,0x28,0xaf,0xe9,0xb4,0x2e,0xb5,0x3c,0x42,0x24,0x86,0xa3 };
|
||||
*/
|
||||
|
||||
extern "C" int ZT_TestCrypto()
|
||||
{
|
||||
static uint8_t buf1[16384],buf2[16384],buf3[16384];
|
||||
static char hexbuf[1024];
|
||||
|
||||
for(int i=0;i<3;++i) {
|
||||
Utils::getSecureRandom(buf1,64);
|
||||
std::cout << "[crypto] getSecureRandom: " << Utils::hex(buf1,64,hexbuf) << ZT_EOL_S;
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "[crypto] Testing Salsa20... "; std::cout.flush();
|
||||
for(unsigned int i=0;i<4;++i) {
|
||||
for(unsigned int k=0;k<sizeof(buf1);++k)
|
||||
buf1[k] = (unsigned char)rand();
|
||||
memset(buf2,0,sizeof(buf2));
|
||||
memset(buf3,0,sizeof(buf3));
|
||||
Salsa20 s20;
|
||||
s20.init("12345678123456781234567812345678","12345678");
|
||||
s20.crypt20(buf1,buf2,sizeof(buf1));
|
||||
s20.init("12345678123456781234567812345678","12345678");
|
||||
s20.crypt20(buf2,buf3,sizeof(buf2));
|
||||
if (memcmp(buf1,buf3,sizeof(buf1))) {
|
||||
std::cout << "FAIL (encrypt/decrypt test)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
{
|
||||
Salsa20 s20(s20TV0Key,s20TV0Iv);
|
||||
memset(buf1,0,sizeof(buf1));
|
||||
memset(buf2,0,sizeof(buf2));
|
||||
s20.crypt20(buf1,buf2,64);
|
||||
if (memcmp(buf2,s20TV0Ks,64)) {
|
||||
std::cout << "FAIL (test vector 0)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
s20.init(s2012TV0Key,s2012TV0Iv);
|
||||
memset(buf1,0,sizeof(buf1));
|
||||
memset(buf2,0,sizeof(buf2));
|
||||
s20.crypt12(buf1,buf2,64);
|
||||
if (memcmp(buf2,s2012TV0Ks,64)) {
|
||||
std::cout << "FAIL (test vector 1)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
}
|
||||
|
||||
#ifdef ZT_SALSA20_SSE
|
||||
std::cout << "[crypto] Salsa20 SSE: ENABLED" ZT_EOL_S;
|
||||
#else
|
||||
std::cout << "[crypto] Salsa20 SSE: DISABLED" ZT_EOL_S;
|
||||
#endif
|
||||
|
||||
std::cout << "[crypto] Benchmarking Salsa20/12... "; std::cout.flush();
|
||||
{
|
||||
unsigned char *bb = (unsigned char *)::malloc(1234567);
|
||||
for(unsigned int i=0;i<1234567;++i)
|
||||
bb[i] = (unsigned char)i;
|
||||
Salsa20 s20(s20TV0Key,s20TV0Iv);
|
||||
long double bytes = 0.0;
|
||||
int64_t start = OSUtils::now();
|
||||
for(unsigned int i=0;i<200;++i) {
|
||||
s20.crypt12(bb,bb,1234567);
|
||||
bytes += 1234567.0;
|
||||
}
|
||||
int64_t end = OSUtils::now();
|
||||
SHA512(buf1,bb,1234567);
|
||||
std::cout << ((bytes / 1048576.0) / ((long double)(end - start) / 1000.0)) << " MiB/second (" << Utils::hex(buf1,16,hexbuf) << ')' << ZT_EOL_S;
|
||||
::free((void *)bb);
|
||||
}
|
||||
|
||||
std::cout << "[crypto] Benchmarking Salsa20/20... "; std::cout.flush();
|
||||
{
|
||||
unsigned char *bb = (unsigned char *)::malloc(1234567);
|
||||
for(unsigned int i=0;i<1234567;++i)
|
||||
bb[i] = (unsigned char)i;
|
||||
Salsa20 s20(s20TV0Key,s20TV0Iv);
|
||||
long double bytes = 0.0;
|
||||
int64_t start = OSUtils::now();
|
||||
for(unsigned int i=0;i<200;++i) {
|
||||
s20.crypt20(bb,bb,1234567);
|
||||
bytes += 1234567.0;
|
||||
}
|
||||
int64_t end = OSUtils::now();
|
||||
SHA512(buf1,bb,1234567);
|
||||
std::cout << ((bytes / 1048576.0) / ((long double)(end - start) / 1000.0)) << " MiB/second (" << Utils::hex(buf1,16,hexbuf) << ')' << ZT_EOL_S;
|
||||
::free((void *)bb);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "[crypto] Testing SHA-512... "; std::cout.flush();
|
||||
SHA512(buf1,sha512TV0Input,(unsigned int)strlen(sha512TV0Input));
|
||||
if (memcmp(buf1,sha512TV0Digest,64)) {
|
||||
std::cout << "FAIL" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
std::cout << "[crypto] Benchmarking SHA-512 (64 byte input)... "; std::cout.flush();
|
||||
int64_t start = OSUtils::now();
|
||||
for(unsigned int i=0;i<2000000;++i) {
|
||||
SHA512(buf1,buf1,64);
|
||||
}
|
||||
int64_t end = OSUtils::now();
|
||||
std::cout << (uint64_t)(2000000.0 / ((double)(end - start) / 1000.0)) << " hashes/second" ZT_EOL_S;
|
||||
|
||||
std::cout << "[crypto] Testing SHA-384... "; std::cout.flush();
|
||||
SHA384(buf1,sha512TV0Input,(unsigned int)strlen(sha512TV0Input));
|
||||
if (memcmp(buf1,sha384TV0Digest,48)) {
|
||||
std::cout << "FAIL" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
std::cout << "[crypto] Benchmarking SHA-384 (48 byte input)... "; std::cout.flush();
|
||||
start = OSUtils::now();
|
||||
for(unsigned int i=0;i<2000000;++i) {
|
||||
SHA384(buf1,buf1,48);
|
||||
}
|
||||
end = OSUtils::now();
|
||||
std::cout << (uint64_t)(2000000.0 / ((double)(end - start) / 1000.0)) << " hashes/second" ZT_EOL_S;
|
||||
|
||||
std::cout << "[crypto] Benchmarking HMAC-SHA384 (2800 byte messages)... "; std::cout.flush();
|
||||
start = OSUtils::now();
|
||||
for(unsigned int i=0;i<200000;++i) {
|
||||
HMACSHA384((const uint8_t *)hexbuf,buf1,2800,buf2);
|
||||
hexbuf[0] = buf2[0]; // begone, optimizer!
|
||||
}
|
||||
end = OSUtils::now();
|
||||
std::cout << (uint64_t)(((200000.0 * 2800.0) / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second" ZT_EOL_S;
|
||||
|
||||
std::cout << "[crypto] Testing Poly1305... "; std::cout.flush();
|
||||
poly1305(buf1,poly1305TV0Input,sizeof(poly1305TV0Input),poly1305TV0Key);
|
||||
if (memcmp(buf1,poly1305TV0Tag,16)) {
|
||||
std::cout << "FAIL (1)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
poly1305(buf1,poly1305TV1Input,sizeof(poly1305TV1Input),poly1305TV1Key);
|
||||
if (memcmp(buf1,poly1305TV1Tag,16)) {
|
||||
std::cout << "FAIL (2)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
|
||||
std::cout << "[crypto] Benchmarking Poly1305... "; std::cout.flush();
|
||||
{
|
||||
unsigned char *bb = (unsigned char *)::malloc(1234567);
|
||||
for(unsigned int i=0;i<1234567;++i)
|
||||
bb[i] = (unsigned char)i;
|
||||
long double bytes = 0.0;
|
||||
uint64_t start = OSUtils::now();
|
||||
for(unsigned int i=0;i<200;++i) {
|
||||
poly1305(buf1,bb,1234567,poly1305TV0Key);
|
||||
bytes += 1234567.0;
|
||||
}
|
||||
uint64_t end = OSUtils::now();
|
||||
std::cout << ((bytes / 1048576.0) / ((long double)(end - start) / 1000.0)) << " MiB/second" ZT_EOL_S;
|
||||
::free((void *)bb);
|
||||
}
|
||||
|
||||
std::cout << "[crypto] Testing C25519 and Ed25519... "; std::cout.flush();
|
||||
for(int k=0;k<ZT_NUM_C25519_TEST_VECTORS;++k) {
|
||||
uint8_t pub1[ZT_C25519_PUBLIC_KEY_LEN],pub2[ZT_C25519_PUBLIC_KEY_LEN],priv1[ZT_C25519_PRIVATE_KEY_LEN],priv2[ZT_C25519_PRIVATE_KEY_LEN];
|
||||
memcpy(pub1,C25519_TEST_VECTORS[k].pub1,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(priv1,C25519_TEST_VECTORS[k].priv1,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
memcpy(pub2,C25519_TEST_VECTORS[k].pub2,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(priv2,C25519_TEST_VECTORS[k].priv2,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
uint8_t ag1[32],ag2[32];
|
||||
C25519::agree(priv1,pub2,ag1);
|
||||
C25519::agree(priv2,pub1,ag2);
|
||||
if (memcmp(ag1,ag2,32) != 0) {
|
||||
std::cout << "FAIL (1)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
uint8_t ag1h[64];
|
||||
SHA512(ag1h,ag1,32);
|
||||
if (memcmp(ag1h,C25519_TEST_VECTORS[k].agreement,64) != 0) {
|
||||
std::cout << "FAIL (2)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
uint8_t sig1[ZT_C25519_SIGNATURE_LEN],sig2[ZT_C25519_SIGNATURE_LEN];
|
||||
C25519::sign(priv1,pub1,ag1h,64,sig1);
|
||||
C25519::sign(priv2,pub2,ag1h,64,sig2);
|
||||
if (memcmp(sig1,C25519_TEST_VECTORS[k].agreementSignedBy1,64) != 0) {
|
||||
std::cout << "FAIL (3)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(sig2,C25519_TEST_VECTORS[k].agreementSignedBy2,64) != 0) {
|
||||
std::cout << "FAIL (4)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
|
||||
std::cout << "[crypto] Testing NIST P-384..." ZT_EOL_S;
|
||||
{
|
||||
uint8_t p384pub[ZT_ECC384_PUBLIC_KEY_SIZE],p384priv[ZT_ECC384_PRIVATE_KEY_SIZE],p384sig[ZT_ECC384_SIGNATURE_SIZE],p384hash[ZT_ECC384_SIGNATURE_HASH_SIZE];
|
||||
char p384hex[256];
|
||||
ECC384GenerateKey(p384pub,p384priv);
|
||||
std::cout << "[crypto] Public Key: " << Utils::hex(p384pub,sizeof(p384pub),p384hex) << ZT_EOL_S;
|
||||
Utils::getSecureRandom(p384hash,sizeof(p384hash));
|
||||
ECC384ECDSASign(p384priv,p384hash,p384sig);
|
||||
if (!ECC384ECDSAVerify(p384pub,p384hash,p384sig)) {
|
||||
std::cout << "[crypto] ECDSA Signature: FAILED (verify good signature)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
++p384sig[0];
|
||||
if (ECC384ECDSAVerify(p384pub,p384hash,p384sig)) {
|
||||
std::cout << "[crypto] ECDSA Signature: FAILED (verify bad signature)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
--p384sig[0];
|
||||
std::cout << "[crypto] ECDSA Signature: " << Utils::hex(p384sig,sizeof(p384sig),p384hex) << ZT_EOL_S;
|
||||
uint8_t p384pub2[ZT_ECC384_PUBLIC_KEY_SIZE],p384priv2[ZT_ECC384_PRIVATE_KEY_SIZE],p384sec[ZT_ECC384_SHARED_SECRET_SIZE],p384sec2[ZT_ECC384_SHARED_SECRET_SIZE];
|
||||
ECC384GenerateKey(p384pub2,p384priv2);
|
||||
ECC384ECDH(p384pub,p384priv2,p384sec);
|
||||
ECC384ECDH(p384pub2,p384priv,p384sec2);
|
||||
if (memcmp(p384sec,p384sec2,ZT_ECC384_SHARED_SECRET_SIZE)) {
|
||||
std::cout << "[crypto] ECDH Agree: FAILED (secrets do not match)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "[crypto] ECDH Agree: " << Utils::hex(p384sec,sizeof(p384sec),p384hex) << ZT_EOL_S;
|
||||
|
||||
Utils::unhex(ECC384_TEST_PUBLIC,strlen(ECC384_TEST_PUBLIC),p384pub,sizeof(p384pub));
|
||||
Utils::unhex(ECC384_TEST_PRIVATE,strlen(ECC384_TEST_PRIVATE),p384priv,sizeof(p384priv));
|
||||
ECC384ECDH(p384pub,p384priv,p384sec);
|
||||
Utils::unhex(ECC384_TEST_DH_SELF_AGREE,strlen(ECC384_TEST_DH_SELF_AGREE),p384sec2,sizeof(p384sec2));
|
||||
if (memcmp(p384sec,p384sec2,ZT_ECC384_SHARED_SECRET_SIZE)) {
|
||||
std::cout << "[crypto] ECDH Test Vector: FAILED (secrets do not match)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "[crypto] ECDH Test Vector: PASS" ZT_EOL_S;
|
||||
Utils::unhex(ECC384_TEST_SIG,strlen(ECC384_TEST_SIG),p384sig,sizeof(p384sig));
|
||||
if (!ECC384ECDSAVerify(p384pub,p384pub,p384sig)) {
|
||||
std::cout << "[crypto] ECDSA Test Vector: FAILED (verify failed)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "[crypto] ECDSA Test Vector: PASS" ZT_EOL_S;
|
||||
}
|
||||
|
||||
std::cout << "[crypto] Benchmarking asymmetric crypto..." ZT_EOL_S;
|
||||
{
|
||||
uint8_t pub[128],priv[128],hash[128],sig[128];
|
||||
Utils::getSecureRandom(hash,sizeof(hash));
|
||||
|
||||
C25519::generate(pub,priv);
|
||||
int64_t start = OSUtils::now();
|
||||
for(int k=0;k<1500;++k) {
|
||||
++hash[0];
|
||||
C25519::sign(priv,pub,hash,sizeof(hash),sig);
|
||||
foo = sig[0];
|
||||
}
|
||||
int64_t end = OSUtils::now();
|
||||
std::cout << " Ed25519 sign: " << (1500.0 / ((double)(end - start) / 1000.0)) << " signatures/second" ZT_EOL_S;
|
||||
start = OSUtils::now();
|
||||
for(int k=0;k<1000;++k) {
|
||||
++sig[0];
|
||||
foo = (uint8_t)C25519::verify(pub,hash,sizeof(hash),sig,ZT_C25519_SIGNATURE_LEN);
|
||||
}
|
||||
end = OSUtils::now();
|
||||
std::cout << " Ed25519 verify: " << (1000.0 / ((double)(end - start) / 1000.0)) << " verifications/second" ZT_EOL_S;
|
||||
start = OSUtils::now();
|
||||
for(int k=0;k<1000;++k) {
|
||||
C25519::agree(priv,pub,hash);
|
||||
foo = hash[0];
|
||||
}
|
||||
end = OSUtils::now();
|
||||
std::cout << " C25519 ECDH: " << (1000.0 / ((double)(end - start) / 1000.0)) << " agreements/second" ZT_EOL_S;
|
||||
|
||||
ECC384GenerateKey(pub,priv);
|
||||
start = OSUtils::now();
|
||||
for(int k=0;k<1000;++k) {
|
||||
++hash[0];
|
||||
ECC384ECDSASign(priv,hash,sig);
|
||||
foo = sig[0];
|
||||
}
|
||||
end = OSUtils::now();
|
||||
std::cout << " ECC P-384 sign: " << (1000.0 / ((double)(end - start) / 1000.0)) << " signatures/second" ZT_EOL_S;
|
||||
start = OSUtils::now();
|
||||
for(int k=0;k<1000;++k) {
|
||||
foo = ECC384ECDSAVerify(pub,hash,sig);
|
||||
}
|
||||
end = OSUtils::now();
|
||||
std::cout << " ECC P-384 verify: " << (1000.0 / ((double)(end - start) / 1000.0)) << " verifications/second" ZT_EOL_S;
|
||||
start = OSUtils::now();
|
||||
for(int k=0;k<1000;++k) {
|
||||
ECC384ECDH(pub,priv,hash);
|
||||
foo = hash[0];
|
||||
}
|
||||
end = OSUtils::now();
|
||||
std::cout << " ECC P-384 ECDH: " << (1000.0 / ((double)(end - start) / 1000.0)) << " agreements/second" ZT_EOL_S;
|
||||
}
|
||||
|
||||
std::cout.flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int ZT_TestIdentity()
|
||||
{
|
||||
Identity id;
|
||||
char buf2[1024];
|
||||
|
||||
std::cout << "[identity] Validate known-good identity... "; std::cout.flush();
|
||||
if (!id.fromString(KNOWN_GOOD_IDENTITY_0)) {
|
||||
std::cout << "FAIL (1)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
const uint64_t vst = OSUtils::now();
|
||||
for(int k=0;k<10;++k) {
|
||||
if (!id.locallyValidate()) {
|
||||
std::cout << "FAIL (2)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
const uint64_t vet = OSUtils::now();
|
||||
std::cout << "PASS (" << ((double)(vet - vst) / 10.0) << "ms per validation)" ZT_EOL_S;
|
||||
|
||||
std::cout << "[identity] Validate known-bad identity... "; std::cout.flush();
|
||||
if (!id.fromString(KNOWN_BAD_IDENTITY_0)) {
|
||||
std::cout << "FAIL (1)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
if (id.locallyValidate()) {
|
||||
std::cout << "FAIL (2)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "PASS (i.e. it failed)" ZT_EOL_S;
|
||||
|
||||
static const Identity::Type idtypes[2] = { Identity::C25519,Identity::P384 };
|
||||
for(unsigned int ti=0;ti<2;++ti) {
|
||||
for(unsigned int k=0;k<2;++k) {
|
||||
std::cout << "[identity] Generate identity (type " << (int)idtypes[ti] << ")... "; std::cout.flush();
|
||||
uint64_t genstart = OSUtils::now();
|
||||
id.generate(idtypes[ti]);
|
||||
uint64_t genend = OSUtils::now();
|
||||
std::cout << "(took " << (genend - genstart) << "ms): " << id.toString(true,buf2) << ZT_EOL_S;
|
||||
std::cout << "[identity] Locally validate identity: ";
|
||||
if (id.locallyValidate()) {
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
} else {
|
||||
std::cout << "FAIL" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
Identity id2;
|
||||
buf.clear();
|
||||
id.serialize(buf,true);
|
||||
id2.deserialize(buf);
|
||||
std::cout << "[identity] Serialize and deserialize (w/private): ";
|
||||
if ((id == id2)&&(id2.locallyValidate())) {
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
} else {
|
||||
std::cout << "FAIL" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Identity id2;
|
||||
buf.clear();
|
||||
id.serialize(buf,false);
|
||||
id2.deserialize(buf);
|
||||
std::cout << "[identity] Serialize and deserialize (no private): ";
|
||||
if ((id == id2)&&(id2.locallyValidate())) {
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
} else {
|
||||
std::cout << "FAIL" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
Identity id2;
|
||||
id2.fromString(id.toString(true,buf2));
|
||||
std::cout << "[identity] Serialize and deserialize (ASCII w/private): ";
|
||||
if ((id == id2)&&(id2.locallyValidate())) {
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
} else {
|
||||
std::cout << "FAIL" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Identity id2;
|
||||
id2.fromString(id.toString(false,buf2));
|
||||
std::cout << "[identity] Serialize and deserialize (ASCII no private): ";
|
||||
if ((id == id2)&&(id2.locallyValidate())) {
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
} else {
|
||||
std::cout << "FAIL" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout.flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int ZT_TestOther()
|
||||
{
|
||||
char buf[1024];
|
||||
char buf2[4096];
|
||||
char buf3[1024];
|
||||
|
||||
std::cout << "[other] Testing Mutex and threads... "; std::cout.flush();
|
||||
volatile unsigned long mcnt = 0;
|
||||
Mutex mlock;
|
||||
std::vector<std::thread> mthr;
|
||||
for(int t=0;t<128;++t) {
|
||||
mthr.emplace_back(std::thread([&mcnt,&mlock]() {
|
||||
for(int i=0;i<10000;++i) {
|
||||
mlock.lock();
|
||||
++mcnt;
|
||||
mlock.unlock();
|
||||
usleep(1);
|
||||
}
|
||||
}));
|
||||
}
|
||||
for(std::vector<std::thread>::iterator t(mthr.begin());t!=mthr.end();++t)
|
||||
t->join();
|
||||
std::cout << "OK (" << mcnt << ")" ZT_EOL_S;
|
||||
|
||||
std::cout << "[other] Testing bit counting functions... "; std::cout.flush();
|
||||
uint32_t i32 = 0;
|
||||
uint64_t i64 = 0;
|
||||
for(int i=0;i<=32;++i) {
|
||||
if ((int)Utils::countBits(i32) != i) {
|
||||
std::cout << "FAIL!" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
i32 <<= 1;
|
||||
i32 |= 1;
|
||||
}
|
||||
for(int i=0;i<=64;++i) {
|
||||
if ((int)Utils::countBits(i64) != i) {
|
||||
std::cout << "FAIL!" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
i64 <<= 1;
|
||||
i64 |= 1;
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
|
||||
std::cout << "[other] Testing hex/unhex... "; std::cout.flush();
|
||||
Utils::getSecureRandom(buf,(unsigned int)sizeof(buf));
|
||||
Utils::hex(buf,(unsigned int)sizeof(buf),buf2);
|
||||
Utils::unhex(buf2,sizeof(buf2),buf3,(unsigned int)sizeof(buf3));
|
||||
if (memcmp(buf,buf3,sizeof(buf)) == 0) {
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
} else {
|
||||
std::cout << "FAIL!" ZT_EOL_S;
|
||||
buf2[78] = 0;
|
||||
std::cout << buf2 << ZT_EOL_S;
|
||||
Utils::hex(buf3,(unsigned int)sizeof(buf3),buf2);
|
||||
buf2[78] = 0;
|
||||
std::cout << buf2 << ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "[other] Testing base32... "; std::cout.flush();
|
||||
for(unsigned int i=1;i<1024;++i) {
|
||||
Utils::getSecureRandom(buf,(unsigned int)sizeof(buf));
|
||||
int l = Utils::b32e((const uint8_t *)buf,i,buf2,sizeof(buf2));
|
||||
if (l <= 0) {
|
||||
std::cout << "FAIL (encode returned 0)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
int l2 = Utils::b32d(buf2,(uint8_t *)buf3,sizeof(buf3));
|
||||
if (l2 != (int)i) {
|
||||
std::cout << "FAIL (decode returned wrong count)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(buf,buf3,i) != 0) {
|
||||
std::cout << "FAIL (decode result incorrect)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
|
||||
std::cout << "[other] Testing InetAddress encode/decode..."; std::cout.flush();
|
||||
std::cout << " " << InetAddress("127.0.0.1/9993").toString(buf);
|
||||
std::cout << " " << InetAddress("feed:dead:babe:dead:beef:f00d:1234:5678/12345").toString(buf);
|
||||
std::cout << " " << InetAddress("0/9993").toString(buf);
|
||||
std::cout << " " << InetAddress("").toString(buf);
|
||||
std::cout << ZT_EOL_S;
|
||||
|
||||
std::cout.flush();
|
||||
return 0;
|
||||
}
|
|
@ -1,399 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#ifndef ZT_HASHTABLE_HPP
|
||||
#define ZT_HASHTABLE_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* A minimal hash table implementation for the ZeroTier core
|
||||
*
|
||||
* This is optimized for smaller data sets.
|
||||
*/
|
||||
template<typename K,typename V>
|
||||
class Hashtable
|
||||
{
|
||||
private:
|
||||
struct _Bucket
|
||||
{
|
||||
ZT_INLINE _Bucket(const K &k,const V &v) : k(k),v(v) {}
|
||||
explicit ZT_INLINE _Bucket(const K &k) : k(k),v() {}
|
||||
ZT_INLINE _Bucket(const _Bucket &b) : k(b.k),v(b.v) {}
|
||||
ZT_INLINE _Bucket &operator=(const _Bucket &b) { k = b.k; v = b.v; return *this; }
|
||||
_Bucket *next; // must be set manually for each _Bucket
|
||||
const K k;
|
||||
V v;
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* A simple forward iterator (different from STL)
|
||||
*
|
||||
* It's safe to erase the last key, but not others. Don't use set() since that
|
||||
* may rehash and invalidate the iterator. Note the erasing the key will destroy
|
||||
* the targets of the pointers returned by next().
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param ht Hash table to iterate over
|
||||
*/
|
||||
explicit ZT_INLINE Iterator(Hashtable &ht) noexcept :
|
||||
_idx(0),
|
||||
_ht(&ht),
|
||||
_b(ht._t[0])
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param kptr Pointer to set to point to next key
|
||||
* @param vptr Pointer to set to point to next value
|
||||
* @return True if kptr and vptr are set, false if no more entries
|
||||
*/
|
||||
ZT_INLINE bool next(K *&kptr,V *&vptr)
|
||||
{
|
||||
for(;;) {
|
||||
if (_b) {
|
||||
kptr = (K *)(&(_b->k));
|
||||
vptr = (V *)(&(_b->v));
|
||||
_b = _b->next;
|
||||
return true;
|
||||
}
|
||||
++_idx;
|
||||
if (_idx >= _ht->_bc)
|
||||
return false;
|
||||
_b = _ht->_t[_idx];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned long _idx;
|
||||
Hashtable *_ht;
|
||||
_Bucket *_b;
|
||||
};
|
||||
//friend class Hashtable<K,V>::Iterator;
|
||||
|
||||
/**
|
||||
* @param bc Initial capacity in buckets (default: 32, must be nonzero)
|
||||
*/
|
||||
explicit ZT_INLINE Hashtable(unsigned int bc = 32) :
|
||||
_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))),
|
||||
_bc(bc),
|
||||
_s(0)
|
||||
{
|
||||
if (!_t)
|
||||
throw std::bad_alloc();
|
||||
Utils::zero(_t,sizeof(uintptr_t) * bc);
|
||||
}
|
||||
|
||||
ZT_INLINE Hashtable(const Hashtable<K,V> &ht) :
|
||||
Hashtable()
|
||||
{
|
||||
*this = ht;
|
||||
}
|
||||
|
||||
ZT_INLINE ~Hashtable()
|
||||
{
|
||||
this->clear();
|
||||
::free(_t);
|
||||
}
|
||||
|
||||
ZT_INLINE Hashtable &operator=(const Hashtable<K,V> &ht)
|
||||
{
|
||||
this->clear();
|
||||
if (ht._s) {
|
||||
for(unsigned long i=0;i<ht._bc;++i) {
|
||||
const _Bucket *b = ht._t[i];
|
||||
while (b) {
|
||||
this->set(b->k,b->v);
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase all entries
|
||||
*/
|
||||
ZT_INLINE void clear()
|
||||
{
|
||||
if (_s) {
|
||||
for(unsigned long i=0;i<_bc;++i) {
|
||||
_Bucket *b = _t[i];
|
||||
while (b) {
|
||||
_Bucket *const nb = b->next;
|
||||
delete b;
|
||||
b = nb;
|
||||
}
|
||||
_t[i] = (_Bucket *)0;
|
||||
}
|
||||
_s = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vector of all keys
|
||||
*/
|
||||
ZT_INLINE typename std::vector<K> keys() const
|
||||
{
|
||||
typename std::vector<K> k;
|
||||
if (_s) {
|
||||
k.reserve(_s);
|
||||
for(unsigned long i=0;i<_bc;++i) {
|
||||
_Bucket *b = _t[i];
|
||||
while (b) {
|
||||
k.push_back(b->k);
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append all keys (in unspecified order) to the supplied vector or list
|
||||
*
|
||||
* @param v Vector, list, or other compliant container
|
||||
* @tparam Type of V (generally inferred)
|
||||
*/
|
||||
template<typename C>
|
||||
ZT_INLINE void appendKeys(C &v) const
|
||||
{
|
||||
if (_s) {
|
||||
for(unsigned long i=0;i<_bc;++i) {
|
||||
_Bucket *b = _t[i];
|
||||
while (b) {
|
||||
v.push_back(b->k);
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vector of all entries (pairs of K,V)
|
||||
*/
|
||||
ZT_INLINE typename std::vector< std::pair<K,V> > entries() const
|
||||
{
|
||||
typename std::vector< std::pair<K,V> > k;
|
||||
if (_s) {
|
||||
k.reserve(_s);
|
||||
for(unsigned long i=0;i<_bc;++i) {
|
||||
_Bucket *b = _t[i];
|
||||
while (b) {
|
||||
k.push_back(std::pair<K,V>(b->k,b->v));
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param k Key
|
||||
* @return Pointer to value or NULL if not found
|
||||
*/
|
||||
ZT_INLINE V *get(const K k)
|
||||
{
|
||||
_Bucket *b = _t[_hc(k) % _bc];
|
||||
while (b) {
|
||||
if (b->k == k)
|
||||
return &(b->v);
|
||||
b = b->next;
|
||||
}
|
||||
return (V *)0;
|
||||
}
|
||||
ZT_INLINE const V *get(const K k) const { return const_cast<Hashtable *>(this)->get(k); }
|
||||
|
||||
/**
|
||||
* @param k Key
|
||||
* @param v Value to fill with result
|
||||
* @return True if value was found and set (if false, v is not modified)
|
||||
*/
|
||||
ZT_INLINE bool get(const K &k,V &v) const
|
||||
{
|
||||
_Bucket *b = _t[_hc(k) % _bc];
|
||||
while (b) {
|
||||
if (b->k == k) {
|
||||
v = b->v;
|
||||
return true;
|
||||
}
|
||||
b = b->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param k Key to check
|
||||
* @return True if key is present
|
||||
*/
|
||||
ZT_INLINE bool contains(const K &k) const
|
||||
{
|
||||
_Bucket *b = _t[_hc(k) % _bc];
|
||||
while (b) {
|
||||
if (b->k == k)
|
||||
return true;
|
||||
b = b->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param k Key
|
||||
* @return True if value was present
|
||||
*/
|
||||
ZT_INLINE bool erase(const K &k)
|
||||
{
|
||||
const unsigned long bidx = _hc(k) % _bc;
|
||||
_Bucket *lastb = (_Bucket *)0;
|
||||
_Bucket *b = _t[bidx];
|
||||
while (b) {
|
||||
if (b->k == k) {
|
||||
if (lastb)
|
||||
lastb->next = b->next;
|
||||
else _t[bidx] = b->next;
|
||||
delete b;
|
||||
--_s;
|
||||
return true;
|
||||
}
|
||||
lastb = b;
|
||||
b = b->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param k Key
|
||||
* @param v Value
|
||||
* @return Reference to value in table
|
||||
*/
|
||||
ZT_INLINE V &set(const K &k,const V &v)
|
||||
{
|
||||
const unsigned long h = _hc(k);
|
||||
unsigned long bidx = h % _bc;
|
||||
|
||||
_Bucket *b = _t[bidx];
|
||||
while (b) {
|
||||
if (b->k == k) {
|
||||
b->v = v;
|
||||
return b->v;
|
||||
}
|
||||
b = b->next;
|
||||
}
|
||||
|
||||
if (_s >= _bc) {
|
||||
_grow();
|
||||
bidx = h % _bc;
|
||||
}
|
||||
|
||||
b = new _Bucket(k,v);
|
||||
b->next = _t[bidx];
|
||||
_t[bidx] = b;
|
||||
++_s;
|
||||
return b->v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param k Key
|
||||
* @return Value, possibly newly created
|
||||
*/
|
||||
ZT_INLINE V &operator[](const K k)
|
||||
{
|
||||
const unsigned long h = _hc(k);
|
||||
unsigned long bidx = h % _bc;
|
||||
|
||||
_Bucket *b = _t[bidx];
|
||||
while (b) {
|
||||
if (b->k == k)
|
||||
return b->v;
|
||||
b = b->next;
|
||||
}
|
||||
|
||||
if (_s >= _bc) {
|
||||
_grow();
|
||||
bidx = h % _bc;
|
||||
}
|
||||
|
||||
b = new _Bucket(k);
|
||||
b->next = _t[bidx];
|
||||
_t[bidx] = b;
|
||||
++_s;
|
||||
return b->v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of entries
|
||||
*/
|
||||
ZT_INLINE unsigned long size() const noexcept { return _s; }
|
||||
|
||||
/**
|
||||
* @return True if table is empty
|
||||
*/
|
||||
ZT_INLINE bool empty() const noexcept { return (_s == 0); }
|
||||
|
||||
private:
|
||||
template<typename O>
|
||||
static ZT_INLINE unsigned long _hc(const O &obj) { return (unsigned long)obj.hashCode(); }
|
||||
static ZT_INLINE unsigned long _hc(const uint64_t i) noexcept { return (unsigned long)(i + (i >> 32U)); }
|
||||
static ZT_INLINE unsigned long _hc(const uint32_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
|
||||
static ZT_INLINE unsigned long _hc(const uint16_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
|
||||
static ZT_INLINE unsigned long _hc(const uint8_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
|
||||
static ZT_INLINE unsigned long _hc(const int64_t i) noexcept { return (unsigned long)((unsigned long long)i + ((unsigned long long)i >> 32U)); }
|
||||
static ZT_INLINE unsigned long _hc(const int32_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
|
||||
static ZT_INLINE unsigned long _hc(const int16_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
|
||||
static ZT_INLINE unsigned long _hc(const int8_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
|
||||
static ZT_INLINE unsigned long _hc(void *p) noexcept { return ((unsigned long)((uintptr_t)p) * (unsigned long)0x9e3779b1); }
|
||||
static ZT_INLINE unsigned long _hc(const void *p) noexcept { return ((unsigned long)((uintptr_t)p) * (unsigned long)0x9e3779b1); }
|
||||
|
||||
ZT_INLINE void _grow()
|
||||
{
|
||||
const unsigned long nc = _bc * 2;
|
||||
_Bucket **nt = reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * nc));
|
||||
if (nt) {
|
||||
for(unsigned long i=0;i<nc;++i)
|
||||
nt[i] = (_Bucket *)0;
|
||||
for(unsigned long i=0;i<_bc;++i) {
|
||||
_Bucket *b = _t[i];
|
||||
while (b) {
|
||||
_Bucket *const nb = b->next;
|
||||
const unsigned long nidx = _hc(b->k) % nc;
|
||||
b->next = nt[nidx];
|
||||
nt[nidx] = b;
|
||||
b = nb;
|
||||
}
|
||||
}
|
||||
::free(_t);
|
||||
_t = nt;
|
||||
_bc = nc;
|
||||
}
|
||||
}
|
||||
|
||||
_Bucket **_t;
|
||||
unsigned long _bc;
|
||||
unsigned long _s;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
|
@ -1,970 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "IncomingPacket.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Switch.hpp"
|
||||
#include "Peer.hpp"
|
||||
#include "NetworkController.hpp"
|
||||
#include "SelfAwareness.hpp"
|
||||
#include "Salsa20.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "Capability.hpp"
|
||||
#include "Tag.hpp"
|
||||
#include "Revocation.hpp"
|
||||
#include "Trace.hpp"
|
||||
#include "Buf.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
// Macro to avoid calling hton() on values known at compile time.
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U)))
|
||||
#else
|
||||
#define CONST_TO_BE_UINT16(x) ((uint16_t)(x))
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
namespace {
|
||||
|
||||
volatile uint16_t junk = 0;
|
||||
|
||||
void _sendErrorNeedCredentials(IncomingPacket &p,const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid)
|
||||
{
|
||||
ZT_GET_NEW_BUF(outp,Protocol::ERROR::NEED_MEMBERSHIP_CERTIFICATE);
|
||||
|
||||
outp->data.fields.h.packetId = Protocol::getPacketId();
|
||||
peer->address().copyTo(outp->data.fields.h.destination);
|
||||
RR->identity.address().copyTo(outp->data.fields.h.source);
|
||||
outp->data.fields.h.flags = 0;
|
||||
outp->data.fields.h.verb = Protocol::VERB_ERROR;
|
||||
|
||||
outp->data.fields.eh.inRePacketId = p.idBE;
|
||||
outp->data.fields.eh.inReVerb = p.pkt->data.fields.verb;
|
||||
outp->data.fields.eh.error = Protocol::ERROR_NEED_MEMBERSHIP_CERTIFICATE;
|
||||
outp->data.fields.networkId = nwid;
|
||||
|
||||
Protocol::armor(*outp,sizeof(Protocol::ERROR::NEED_MEMBERSHIP_CERTIFICATE),peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012);
|
||||
p.path->send(RR,tPtr,outp->data.bytes,sizeof(Protocol::ERROR::NEED_MEMBERSHIP_CERTIFICATE),RR->node->now());
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const bool alreadyAuthenticated)
|
||||
{
|
||||
if (p.size < sizeof(Protocol::HELLO)) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,Identity(),p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
Buf< Protocol::HELLO > &pkt = reinterpret_cast<Buf< Protocol::HELLO > &>(*p.pkt);
|
||||
|
||||
Identity id;
|
||||
int ptr = sizeof(Protocol::HELLO);
|
||||
if (pkt.rO(ptr,id) < 0) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,Identity(),p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pkt.data.fields.versionProtocol < ZT_PROTO_VERSION_MIN) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD);
|
||||
return true;
|
||||
}
|
||||
if (Address(pkt.data.fields.h.source) != id.address()) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
|
||||
const int64_t now = RR->node->now();
|
||||
|
||||
SharedPtr<Peer> peer(RR->topology->get(tPtr,id.address()));
|
||||
if (peer) {
|
||||
// We already have an identity with this address -- check for collisions
|
||||
if (!alreadyAuthenticated) {
|
||||
if (peer->identity() != id) {
|
||||
// Identity is different from the one we already have -- address collision
|
||||
|
||||
// Check rate limits
|
||||
if (!RR->node->rateGateIdentityVerification(now,p.path->address()))
|
||||
return true;
|
||||
|
||||
uint8_t key[ZT_PEER_SECRET_KEY_LENGTH];
|
||||
if (RR->identity.agree(id,key)) {
|
||||
if (Protocol::dearmor(pkt,p.size,key) < 0) { // ensure packet is authentic, otherwise drop
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||
return true;
|
||||
} else {
|
||||
// TODO: we handle identity collisions differently now
|
||||
}
|
||||
} else {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// Identity is the same as the one we already have -- check packet integrity
|
||||
|
||||
if (Protocol::dearmor(pkt,p.size,peer->key()) < 0) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Continue at // VALID
|
||||
}
|
||||
} // else if alreadyAuthenticated then continue at // VALID
|
||||
} else {
|
||||
// We don't already have an identity with this address -- validate and learn it
|
||||
|
||||
// Sanity check: this basically can't happen
|
||||
if (alreadyAuthenticated) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,Identity(),p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check rate limits
|
||||
if (!RR->node->rateGateIdentityVerification(now,p.path->address())) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap)
|
||||
SharedPtr<Peer> newPeer(new Peer(RR));
|
||||
if (!newPeer->init(RR->identity,id)) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||
return true;
|
||||
}
|
||||
if (Protocol::dearmor(pkt,p.size,newPeer->key())) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check that identity's address is valid as per the derivation function
|
||||
if (!id.locallyValidate()) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
||||
return true;
|
||||
}
|
||||
|
||||
peer = RR->topology->add(tPtr,newPeer);
|
||||
|
||||
// Continue at // VALID
|
||||
}
|
||||
|
||||
// VALID -- if we made it here, packet passed identity and authenticity checks!
|
||||
|
||||
// Get address to which this packet was sent to learn our external surface address if packet was direct.
|
||||
InetAddress externalSurfaceAddress;
|
||||
if (ptr < p.size) {
|
||||
if (pkt.rO(ptr,externalSurfaceAddress) < 0) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
||||
return true;
|
||||
}
|
||||
if ((p.hops == 0)&&(externalSurfaceAddress))
|
||||
RR->sa->iam(tPtr,id,p.path->localSocket(),p.path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now);
|
||||
}
|
||||
|
||||
// Send OK(HELLO) with an echo of the packet's timestamp and some of the same
|
||||
// information about us: version, sent-to address, etc.
|
||||
|
||||
ZT_GET_NEW_BUF(outp,Protocol::OK::HELLO);
|
||||
|
||||
outp->data.fields.h.packetId = Protocol::getPacketId();
|
||||
peer->address().copyTo(outp->data.fields.h.destination);
|
||||
RR->identity.address().copyTo(outp->data.fields.h.source);
|
||||
outp->data.fields.h.flags = 0;
|
||||
outp->data.fields.h.verb = Protocol::VERB_OK;
|
||||
|
||||
outp->data.fields.oh.inReVerb = Protocol::VERB_HELLO;
|
||||
outp->data.fields.oh.inRePacketId = p.idBE;
|
||||
|
||||
outp->data.fields.timestampEcho = pkt.data.fields.timestamp;
|
||||
outp->data.fields.versionProtocol = ZT_PROTO_VERSION;
|
||||
outp->data.fields.versionMajor = ZEROTIER_ONE_VERSION_MAJOR;
|
||||
outp->data.fields.versionMinor = ZEROTIER_ONE_VERSION_MINOR;
|
||||
outp->data.fields.versionRev = CONST_TO_BE_UINT16(ZEROTIER_ONE_VERSION_REVISION);
|
||||
|
||||
int outl = sizeof(Protocol::OK::HELLO);
|
||||
outp->wO(outl,p.path->address());
|
||||
if (!Buf<>::writeOverflow(outl)) {
|
||||
Protocol::armor(*outp,outl,peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012);
|
||||
p.path->send(RR,tPtr,outp->data.bytes,outl,RR->node->now());
|
||||
}
|
||||
|
||||
peer->setRemoteVersion(pkt.data.fields.versionProtocol,pkt.data.fields.versionMajor,pkt.data.fields.versionMinor,Utils::ntoh(pkt.data.fields.versionRev));
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_HELLO,0,Protocol::VERB_NOP,0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doERROR(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if (p.size < sizeof(Protocol::ERROR::Header)) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_ERROR,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
Buf< Protocol::ERROR::Header > &pkt = reinterpret_cast<Buf< Protocol::ERROR::Header > &>(*p.pkt);
|
||||
|
||||
uint64_t networkId = 0;
|
||||
int ptr = sizeof(Protocol::ERROR::Header);
|
||||
|
||||
/* Security note: we do not gate doERROR() with expectingReplyTo() to
|
||||
* avoid having to log every outgoing packet ID. Instead we put the
|
||||
* logic to determine whether we should consider an ERROR in each
|
||||
* error handler. In most cases these are only trusted in specific
|
||||
* circumstances. */
|
||||
|
||||
switch(pkt.data.fields.error) {
|
||||
|
||||
case Protocol::ERROR_OBJ_NOT_FOUND:
|
||||
// Object not found, currently only meaningful from network controllers.
|
||||
if (pkt.data.fields.inReVerb == Protocol::VERB_NETWORK_CONFIG_REQUEST) {
|
||||
networkId = pkt.rI64(ptr);
|
||||
const SharedPtr<Network> network(RR->node->network(networkId));
|
||||
if ((network)&&(network->controller() == peer->address()))
|
||||
network->setNotFound();
|
||||
}
|
||||
break;
|
||||
|
||||
case Protocol::ERROR_UNSUPPORTED_OPERATION:
|
||||
// This can be sent in response to any operation, though right now we only
|
||||
// consider it meaningful from network controllers. This would indicate
|
||||
// that the queried node does not support acting as a controller.
|
||||
if (pkt.data.fields.inReVerb == Protocol::VERB_NETWORK_CONFIG_REQUEST) {
|
||||
networkId = pkt.rI64(ptr);
|
||||
const SharedPtr<Network> network(RR->node->network(networkId));
|
||||
if ((network)&&(network->controller() == peer->address()))
|
||||
network->setNotFound();
|
||||
}
|
||||
break;
|
||||
|
||||
case Protocol::ERROR_NEED_MEMBERSHIP_CERTIFICATE: {
|
||||
// Peers can send this to ask for a cert for a network.
|
||||
networkId = pkt.rI64(ptr);
|
||||
const SharedPtr<Network> network(RR->node->network(networkId));
|
||||
const int64_t now = RR->node->now();
|
||||
if ((network)&&(network->config().com))
|
||||
network->pushCredentialsNow(tPtr,peer->address(),now);
|
||||
} break;
|
||||
|
||||
case Protocol::ERROR_NETWORK_ACCESS_DENIED_: {
|
||||
// Network controller: network access denied.
|
||||
networkId = pkt.rI64(ptr);
|
||||
const SharedPtr<Network> network(RR->node->network(networkId));
|
||||
if ((network)&&(network->controller() == peer->address()))
|
||||
network->setAccessDenied();
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_ERROR,pkt.data.fields.inRePacketId,(Protocol::Verb)pkt.data.fields.inReVerb,networkId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doOK(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if (p.size < sizeof(Protocol::OK::Header)) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_OK,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
Buf< Protocol::OK::Header > &pkt = reinterpret_cast<Buf< Protocol::OK::Header > &>(*p.pkt);
|
||||
|
||||
uint64_t networkId = 0;
|
||||
int ptr = sizeof(Protocol::OK::Header);
|
||||
|
||||
if (!RR->node->expectingReplyTo(p.idBE))
|
||||
return true;
|
||||
|
||||
switch(pkt.data.fields.inReVerb) {
|
||||
|
||||
case Protocol::VERB_HELLO: {
|
||||
if (p.size < sizeof(Protocol::OK::HELLO)) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
Buf< Protocol::OK::HELLO > &pkt2 = reinterpret_cast<Buf< Protocol::OK::HELLO > &>(pkt);
|
||||
|
||||
if (pkt2.data.fields.versionProtocol < ZT_PROTO_VERSION_MIN)
|
||||
return true;
|
||||
peer->updateLatency((unsigned int)(p.receiveTime - Utils::ntoh(pkt2.data.fields.timestampEcho)));
|
||||
peer->setRemoteVersion(pkt2.data.fields.versionProtocol,pkt2.data.fields.versionMajor,pkt2.data.fields.versionMinor,Utils::ntoh(pkt2.data.fields.versionRev));
|
||||
|
||||
ptr = sizeof(Protocol::OK::HELLO);
|
||||
if (ptr < p.size) {
|
||||
InetAddress externalSurfaceAddress;
|
||||
if (pkt2.rO(ptr,externalSurfaceAddress) < 0)
|
||||
return true;
|
||||
if ((externalSurfaceAddress)&&(p.hops == 0))
|
||||
RR->sa->iam(tPtr,peer->identity(),p.path->localSocket(),p.path->address(),externalSurfaceAddress,RR->topology->isRoot(peer->identity()),RR->node->now());
|
||||
}
|
||||
} break;
|
||||
|
||||
case Protocol::VERB_WHOIS:
|
||||
if (RR->topology->isRoot(peer->identity())) {
|
||||
while (ptr < p.size) {
|
||||
Identity id;
|
||||
if (pkt.rO(ptr,id) < 0)
|
||||
break;
|
||||
Locator loc;
|
||||
if (ptr < p.size) { // older nodes did not send the locator
|
||||
if (pkt.rO(ptr,loc) < 0)
|
||||
break;
|
||||
}
|
||||
if (id) {
|
||||
SharedPtr<Peer> ptmp(RR->topology->add(tPtr,SharedPtr<Peer>(new Peer(RR))));
|
||||
ptmp->init(RR->identity,id);
|
||||
RR->sw->doAnythingWaitingForPeer(tPtr,ptmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Protocol::VERB_NETWORK_CONFIG_REQUEST: {
|
||||
networkId = pkt.rI64(ptr);
|
||||
const SharedPtr<Network> network(RR->node->network(networkId));
|
||||
if (network)
|
||||
network->handleConfigChunk(tPtr,p.idBE,peer,pkt,sizeof(Protocol::OK::Header),(int)p.size);
|
||||
} break;
|
||||
|
||||
case Protocol::VERB_MULTICAST_GATHER: {
|
||||
// TODO
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_OK,pkt.data.fields.inRePacketId,(Protocol::Verb)pkt.data.fields.inReVerb,networkId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doWHOIS(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if (!peer->rateGateInboundWhoisRequest(RR->node->now())) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_WHOIS,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED);
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_GET_NEW_BUF(outp,Protocol::OK::WHOIS);
|
||||
|
||||
outp->data.fields.h.packetId = Protocol::getPacketId();
|
||||
peer->address().copyTo(outp->data.fields.h.destination);
|
||||
RR->identity.address().copyTo(outp->data.fields.h.source);
|
||||
outp->data.fields.h.flags = 0;
|
||||
outp->data.fields.h.verb = Protocol::VERB_OK;
|
||||
|
||||
outp->data.fields.oh.inReVerb = Protocol::VERB_WHOIS;
|
||||
outp->data.fields.oh.inRePacketId = p.idBE;
|
||||
|
||||
int ptr = sizeof(Protocol::Header);
|
||||
int outl = sizeof(Protocol::OK::WHOIS);
|
||||
while ((ptr + ZT_ADDRESS_LENGTH) <= p.size) {
|
||||
const SharedPtr<Peer> ptmp(RR->topology->get(tPtr,Address(p.pkt->data.bytes + ptr)));
|
||||
if (ptmp) {
|
||||
outp->wO(outl,ptmp->identity());
|
||||
Locator loc(ptmp->locator());
|
||||
outp->wO(outl,loc);
|
||||
}
|
||||
ptr += ZT_ADDRESS_LENGTH;
|
||||
}
|
||||
|
||||
if ((outl > sizeof(Protocol::OK::WHOIS))&&(!Buf<>::writeOverflow(outl))) {
|
||||
Protocol::armor(*outp,outl,peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012);
|
||||
p.path->send(RR,tPtr,outp->data.bytes,outl,RR->node->now());
|
||||
}
|
||||
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_WHOIS,0,Protocol::VERB_NOP,0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doRENDEZVOUS(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if (RR->topology->isRoot(peer->identity())) {
|
||||
if (p.size < sizeof(Protocol::RENDEZVOUS)) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_RENDEZVOUS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
Buf< Protocol::RENDEZVOUS > &pkt = reinterpret_cast<Buf< Protocol::RENDEZVOUS > &>(*p.pkt);
|
||||
|
||||
const SharedPtr<Peer> with(RR->topology->get(tPtr,Address(pkt.data.fields.peerAddress)));
|
||||
if (with) {
|
||||
const unsigned int port = Utils::ntoh(pkt.data.fields.port);
|
||||
if (port != 0) {
|
||||
switch(pkt.data.fields.addressLength) {
|
||||
case 4:
|
||||
if ((sizeof(Protocol::RENDEZVOUS) + 4) <= p.size) {
|
||||
InetAddress atAddr(pkt.data.fields.address,4,port);
|
||||
++junk;
|
||||
RR->node->putPacket(tPtr,p.path->localSocket(),atAddr,(const void *)&junk,2,2); // IPv4 "firewall opener" hack
|
||||
with->sendHELLO(tPtr,p.path->localSocket(),atAddr,RR->node->now());
|
||||
RR->t->tryingNewPath(tPtr,with->identity(),atAddr,p.path->address(),p.idBE,Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS);
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
if ((sizeof(Protocol::RENDEZVOUS) + 16) <= p.size) {
|
||||
InetAddress atAddr(pkt.data.fields.address,16,port);
|
||||
with->sendHELLO(tPtr,p.path->localSocket(),atAddr,RR->node->now());
|
||||
RR->t->tryingNewPath(tPtr,with->identity(),atAddr,p.path->address(),p.idBE,Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_RENDEZVOUS,0,Protocol::VERB_NOP,0);
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doFRAME(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if (p.size < sizeof(Protocol::FRAME)) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_EXT_FRAME,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
Buf< Protocol::FRAME > &pkt = reinterpret_cast<Buf< Protocol::FRAME > &>(*p.pkt);
|
||||
|
||||
const SharedPtr<Network> network(RR->node->network(Utils::ntoh(pkt.data.fields.networkId)));
|
||||
if (network) {
|
||||
if (network->gate(tPtr,peer)) {
|
||||
const unsigned int etherType = Utils::ntoh(pkt.data.fields.etherType);
|
||||
const MAC sourceMac(peer->address(),network->id());
|
||||
const unsigned int frameLen = (unsigned int)(p.size - sizeof(Protocol::FRAME));
|
||||
if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),sourceMac,network->mac(),pkt.data.fields.data,frameLen,etherType,0) > 0)
|
||||
RR->node->putFrame(tPtr,network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,pkt.data.fields.data,frameLen);
|
||||
} else {
|
||||
RR->t->incomingNetworkFrameDropped(tPtr,network->id(),MAC(),MAC(),peer->identity(),p.path->address(),p.hops,0,nullptr,Protocol::VERB_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED);
|
||||
_sendErrorNeedCredentials(p,RR,tPtr,peer,network->id());
|
||||
return false; // try to decode again after we get credentials?
|
||||
}
|
||||
}
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_FRAME,0,Protocol::VERB_NOP,0);
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doEXT_FRAME(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if (p.size < sizeof(Protocol::EXT_FRAME)) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_EXT_FRAME,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
Buf< Protocol::EXT_FRAME > &pkt = reinterpret_cast<Buf< Protocol::EXT_FRAME > &>(*p.pkt);
|
||||
|
||||
const SharedPtr<Network> network(RR->node->network(Utils::ntoh(pkt.data.fields.networkId)));
|
||||
if (network) {
|
||||
int ptr = sizeof(Protocol::EXT_FRAME);
|
||||
const uint8_t flags = pkt.data.fields.flags;
|
||||
|
||||
if ((flags & Protocol::EXT_FRAME_FLAG_COM_ATTACHED_deprecated) != 0) {
|
||||
CertificateOfMembership com;
|
||||
if (pkt.rO(ptr,com) < 0) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_EXT_FRAME,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
if (com)
|
||||
network->addCredential(tPtr,peer->identity(),com);
|
||||
}
|
||||
|
||||
if (!network->gate(tPtr,peer)) {
|
||||
RR->t->incomingNetworkFrameDropped(tPtr,network->id(),MAC(),MAC(),peer->identity(),p.path->address(),p.hops,0,nullptr,Protocol::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED);
|
||||
_sendErrorNeedCredentials(p,RR,tPtr,peer,network->id());
|
||||
return false; // try to parse again if we get credentials
|
||||
}
|
||||
|
||||
const MAC to(pkt.rBnc(ptr,6));
|
||||
const MAC from(pkt.rBnc(ptr,6));
|
||||
const unsigned int etherType = pkt.rI16(ptr);
|
||||
|
||||
if ((from)&&(from != network->mac())&&(!Buf<>::readOverflow(ptr,p.size))) {
|
||||
const int frameSize = (int)(p.size - ptr);
|
||||
if (frameSize >= 0) {
|
||||
const uint64_t nwid = network->id();
|
||||
const uint8_t *const frameData = pkt.data.bytes + ptr;
|
||||
switch (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to,frameData,frameSize,etherType,0)) {
|
||||
|
||||
case 1:
|
||||
if (from != MAC(peer->address(),nwid)) {
|
||||
if (network->config().permitsBridging(peer->address())) {
|
||||
network->learnBridgeRoute(from,peer->address());
|
||||
} else {
|
||||
RR->t->incomingNetworkFrameDropped(tPtr,nwid,from,to,peer->identity(),p.path->address(),p.hops,(uint16_t)frameSize,frameData,Protocol::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE);
|
||||
goto packet_dropped;
|
||||
}
|
||||
} else if (to != network->mac()) {
|
||||
if (to.isMulticast()) {
|
||||
if (network->config().multicastLimit == 0) {
|
||||
RR->t->incomingNetworkFrameDropped(tPtr,nwid,from,to,peer->identity(),p.path->address(),p.hops,(uint16_t)frameSize,frameData,Protocol::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED);
|
||||
goto packet_dropped;
|
||||
}
|
||||
} else if (!network->config().permitsBridging(RR->identity.address())) {
|
||||
RR->t->incomingNetworkFrameDropped(tPtr,nwid,from,to,peer->identity(),p.path->address(),p.hops,(uint16_t)frameSize,frameData,Protocol::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL);
|
||||
goto packet_dropped;
|
||||
}
|
||||
}
|
||||
// fall through -- 2 means accept regardless of bridging checks or other restrictions
|
||||
|
||||
case 2:
|
||||
RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to,etherType,0,frameData,frameSize);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & Protocol::EXT_FRAME_FLAG_ACK_REQUESTED) != 0) {
|
||||
ZT_GET_NEW_BUF(outp,Protocol::OK::EXT_FRAME);
|
||||
|
||||
outp->data.fields.h.packetId = Protocol::getPacketId();
|
||||
peer->address().copyTo(outp->data.fields.h.destination);
|
||||
RR->identity.address().copyTo(outp->data.fields.h.source);
|
||||
outp->data.fields.h.flags = 0;
|
||||
outp->data.fields.h.verb = Protocol::VERB_OK;
|
||||
|
||||
outp->data.fields.oh.inReVerb = Protocol::VERB_EXT_FRAME;
|
||||
outp->data.fields.oh.inRePacketId = p.idBE;
|
||||
|
||||
outp->data.fields.networkId = pkt.data.fields.networkId;
|
||||
outp->data.fields.flags = 0;
|
||||
to.copyTo(outp->data.fields.destMac);
|
||||
from.copyTo(outp->data.fields.sourceMac);
|
||||
outp->data.fields.etherType = Utils::hton((uint16_t)etherType);
|
||||
|
||||
Protocol::armor(*outp,sizeof(Protocol::OK::EXT_FRAME),peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012);
|
||||
p.path->send(RR,tPtr,outp->data.bytes,sizeof(Protocol::OK::EXT_FRAME),RR->node->now());
|
||||
}
|
||||
}
|
||||
|
||||
packet_dropped:
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_EXT_FRAME,0,Protocol::VERB_NOP,0);
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doECHO(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if (!peer->rateGateEchoRequest(RR->node->now())) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_ECHO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED);
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_GET_NEW_BUF(outp,Protocol::OK::ECHO);
|
||||
|
||||
outp->data.fields.h.packetId = Protocol::getPacketId();
|
||||
peer->address().copyTo(outp->data.fields.h.destination);
|
||||
RR->identity.address().copyTo(outp->data.fields.h.source);
|
||||
outp->data.fields.h.flags = 0;
|
||||
outp->data.fields.h.verb = Protocol::VERB_OK;
|
||||
|
||||
outp->data.fields.oh.inReVerb = Protocol::VERB_ECHO;
|
||||
outp->data.fields.oh.inRePacketId = p.idBE;
|
||||
|
||||
int outl = sizeof(Protocol::OK::ECHO);
|
||||
if (p.size > sizeof(Protocol::Header)) {
|
||||
outp->wB(outl,p.pkt->data.bytes + sizeof(Protocol::Header),p.size - sizeof(Protocol::Header));
|
||||
}
|
||||
|
||||
if (!Buf<>::writeOverflow(outl)) {
|
||||
Protocol::armor(*outp,outl,peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012);
|
||||
p.path->send(RR,tPtr,outp->data.bytes,outl,RR->node->now());
|
||||
}
|
||||
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_ECHO,0,Protocol::VERB_NOP,0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doNETWORK_CREDENTIALS(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
int ptr = sizeof(Protocol::Header);
|
||||
const uint8_t *payload = p.pkt->data.bytes;
|
||||
SharedPtr<Network> network;
|
||||
|
||||
// Early versions of ZeroTier sent only the certificate of membership. The COM always
|
||||
// starts with a non-zero byte. To extend this message we then parse COMs until we find
|
||||
// a zero byte, then parse the other types (which are prefaced by a count for better
|
||||
// extensibility) if they are present.
|
||||
|
||||
// Also note that technically these can be for different networks but in practice they
|
||||
// are always for the same network (when talking with current nodes). This code therefore
|
||||
// accepts different networks for each credential and ignores any credentials for
|
||||
// networks that we've not currently joined.
|
||||
|
||||
while ((ptr < p.size)&&(payload[ptr] != 0)) {
|
||||
CertificateOfMembership com;
|
||||
int l = com.unmarshal(payload + ptr,(int)(p.size - ptr));
|
||||
if (l < 0) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CREDENTIALS,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
||||
return true;
|
||||
}
|
||||
ptr += l;
|
||||
|
||||
const uint64_t nwid = com.networkId();
|
||||
if ((!network)||(network->id() != nwid))
|
||||
network = RR->node->network(nwid);
|
||||
if (network) {
|
||||
if (network->addCredential(tPtr,peer->identity(),com) == Membership::ADD_DEFERRED_FOR_WHOIS)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++ptr; // skip trailing 0 after COMs if present
|
||||
|
||||
// The following code is copypasta for each credential type: capability, tag, revocation,
|
||||
// and certificate of ownership. Each type is prefaced by a count, but it's legal for the
|
||||
// packet to terminate prematurely if all remaining counts are zero.
|
||||
|
||||
if (ptr >= p.size)
|
||||
return true;
|
||||
|
||||
unsigned int count = p.pkt->rI16(ptr);
|
||||
for(unsigned int i=0;i<count;++i) {
|
||||
if (ptr >= p.size) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CREDENTIALS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
Capability cap;
|
||||
int l = cap.unmarshal(payload + ptr,(int)(p.size - ptr));
|
||||
if (l < 0) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CREDENTIALS,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
||||
return true;
|
||||
}
|
||||
ptr += l;
|
||||
|
||||
const uint64_t nwid = cap.networkId();
|
||||
if ((!network)||(network->id() != nwid))
|
||||
network = RR->node->network(nwid);
|
||||
if (network) {
|
||||
if (network->addCredential(tPtr,peer->identity(),cap) == Membership::ADD_DEFERRED_FOR_WHOIS)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr >= p.size)
|
||||
return true;
|
||||
|
||||
count = p.pkt->rI16(ptr);
|
||||
for(unsigned int i=0;i<count;++i) {
|
||||
if (ptr >= p.size) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CREDENTIALS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
Tag tag;
|
||||
int l = tag.unmarshal(payload + ptr,(int)(p.size - ptr));
|
||||
if (l < 0) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CREDENTIALS,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
||||
return true;
|
||||
}
|
||||
ptr += l;
|
||||
|
||||
const uint64_t nwid = tag.networkId();
|
||||
if ((!network)||(network->id() != nwid))
|
||||
network = RR->node->network(nwid);
|
||||
if (network) {
|
||||
if (network->addCredential(tPtr,peer->identity(),tag) == Membership::ADD_DEFERRED_FOR_WHOIS)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr >= p.size)
|
||||
return true;
|
||||
|
||||
count = p.pkt->rI16(ptr);
|
||||
for(unsigned int i=0;i<count;++i) {
|
||||
if (ptr >= p.size) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CREDENTIALS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
Revocation rev;
|
||||
int l = rev.unmarshal(payload + ptr,(int)(p.size - ptr));
|
||||
if (l < 0) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CREDENTIALS,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
||||
return true;
|
||||
}
|
||||
ptr += l;
|
||||
|
||||
const uint64_t nwid = rev.networkId();
|
||||
if ((!network)||(network->id() != nwid))
|
||||
network = RR->node->network(nwid);
|
||||
if (network) {
|
||||
if (network->addCredential(tPtr,peer->identity(),rev) == Membership::ADD_DEFERRED_FOR_WHOIS)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr >= p.size)
|
||||
return true;
|
||||
|
||||
count = p.pkt->rI16(ptr);
|
||||
for(unsigned int i=0;i<count;++i) {
|
||||
if (ptr >= p.size) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CREDENTIALS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
CertificateOfOwnership coo;
|
||||
int l = coo.unmarshal(payload + ptr,(int)(p.size - ptr));
|
||||
if (l < 0) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CREDENTIALS,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
||||
return true;
|
||||
}
|
||||
ptr += l;
|
||||
|
||||
const uint64_t nwid = coo.networkId();
|
||||
if ((!network)||(network->id() != nwid))
|
||||
network = RR->node->network(nwid);
|
||||
if (network) {
|
||||
if (network->addCredential(tPtr,peer->identity(),coo) == Membership::ADD_DEFERRED_FOR_WHOIS)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_NETWORK_CREDENTIALS,0,Protocol::VERB_NOP,(network) ? network->id() : 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doNETWORK_CONFIG_REQUEST(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
int ptr = sizeof(Protocol::Header);
|
||||
|
||||
const uint64_t nwid = p.pkt->rI64(ptr);
|
||||
const unsigned int dictSize = p.pkt->rI16(ptr);
|
||||
const uint8_t *dictData = p.pkt->rBnc(ptr,dictSize);
|
||||
if (Buf<>::readOverflow(ptr,p.size)) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CONFIG_REQUEST,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (RR->localNetworkController) {
|
||||
Dictionary requestMetaData;
|
||||
if ((dictSize > 0)&&(dictData)) {
|
||||
if (!requestMetaData.decode(dictData,dictSize)) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CONFIG_REQUEST,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
RR->localNetworkController->request(nwid,(p.hops > 0) ? InetAddress::NIL : p.path->address(),Utils::ntoh(p.idBE),peer->identity(),requestMetaData);
|
||||
} else {
|
||||
ZT_GET_NEW_BUF(outp,Protocol::ERROR::UNSUPPORTED_OPERATION__NETWORK_CONFIG_REQUEST);
|
||||
|
||||
outp->data.fields.h.packetId = Protocol::getPacketId();
|
||||
peer->address().copyTo(outp->data.fields.h.destination);
|
||||
RR->identity.address().copyTo(outp->data.fields.h.source);
|
||||
outp->data.fields.h.flags = 0;
|
||||
outp->data.fields.h.verb = Protocol::VERB_OK;
|
||||
|
||||
outp->data.fields.eh.inReVerb = Protocol::VERB_NETWORK_CONFIG_REQUEST;
|
||||
outp->data.fields.eh.inRePacketId = p.idBE;
|
||||
outp->data.fields.eh.error = Protocol::ERROR_UNSUPPORTED_OPERATION;
|
||||
|
||||
outp->data.fields.networkId = Utils::hton(nwid);
|
||||
|
||||
Protocol::armor(*outp,sizeof(Protocol::ERROR::UNSUPPORTED_OPERATION__NETWORK_CONFIG_REQUEST),peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012);
|
||||
p.path->send(RR,tPtr,outp->data.bytes,sizeof(Protocol::ERROR::UNSUPPORTED_OPERATION__NETWORK_CONFIG_REQUEST),RR->node->now());
|
||||
}
|
||||
|
||||
// Note that NETWORK_CONFIG_REQUEST does not pertain to a network we have *joined*, but one
|
||||
// we may control. The network ID parameter to peer->received() is therefore zero.
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_NETWORK_CONFIG_REQUEST,0,Protocol::VERB_NOP,0);
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doNETWORK_CONFIG(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
int ptr = sizeof(Protocol::Header);
|
||||
const uint64_t nwid = p.pkt->rI64(ptr);
|
||||
if (ptr >= (int)p.size) {
|
||||
RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CONFIG,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||
return true;
|
||||
}
|
||||
|
||||
const SharedPtr<Network> network(RR->node->network(nwid));
|
||||
if (network) {
|
||||
const uint64_t configUpdateId = network->handleConfigChunk(tPtr,p.idBE,peer,*p.pkt,ptr,(int)p.size - ptr);
|
||||
if (configUpdateId != 0) {
|
||||
ZT_GET_NEW_BUF(outp,Protocol::OK::NETWORK_CONFIG);
|
||||
|
||||
outp->data.fields.h.packetId = Protocol::getPacketId();
|
||||
peer->address().copyTo(outp->data.fields.h.destination);
|
||||
RR->identity.address().copyTo(outp->data.fields.h.source);
|
||||
outp->data.fields.h.flags = 0;
|
||||
outp->data.fields.h.verb = Protocol::VERB_OK;
|
||||
|
||||
outp->data.fields.oh.inReVerb = Protocol::VERB_NETWORK_CONFIG;
|
||||
outp->data.fields.oh.inRePacketId = p.idBE;
|
||||
|
||||
outp->data.fields.networkId = Utils::hton(nwid);
|
||||
outp->data.fields.configUpdateId = Utils::hton(configUpdateId);
|
||||
|
||||
Protocol::armor(*outp,sizeof(Protocol::OK::NETWORK_CONFIG),peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012);
|
||||
p.path->send(RR,tPtr,outp->data.bytes,sizeof(Protocol::OK::NETWORK_CONFIG),RR->node->now());
|
||||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_NETWORK_CONFIG,0,Protocol::VERB_NOP,nwid);
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doMULTICAST_GATHER(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doPUSH_DIRECT_PATHS(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
/*
|
||||
const int64_t now = RR->node->now();
|
||||
|
||||
if (peer->rateGateInboundPushDirectPaths(now)) {
|
||||
uint8_t countPerScope[ZT_INETADDRESS_MAX_SCOPE+1][2]; // [][0] is v4, [][1] is v6
|
||||
memset(countPerScope,0,sizeof(countPerScope));
|
||||
|
||||
unsigned int count = pkt.at<uint16_t>(ZT_PACKET_IDX_PAYLOAD);
|
||||
unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2;
|
||||
|
||||
while (count--) {
|
||||
// unsigned int flags = (*this)[ptr++];
|
||||
++ptr;
|
||||
unsigned int extLen = pkt.at<uint16_t>(ptr); ptr += 2;
|
||||
ptr += extLen; // unused right now
|
||||
unsigned int addrType = pkt[ptr++];
|
||||
unsigned int addrLen = pkt[ptr++];
|
||||
|
||||
switch(addrType) {
|
||||
case 4: {
|
||||
const InetAddress a(pkt.field(ptr,4),4,pkt.at<uint16_t>(ptr + 4));
|
||||
if (peer->shouldTryPath(tPtr,now,peer,a)) {
|
||||
if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
|
||||
RR->node->putPacket(tPtr,path->localSocket(),a,(const void *)&junk,sizeof(junk),2); // IPv4 "firewall opener"
|
||||
++junk;
|
||||
peer->sendHELLO(tPtr,-1,a,now);
|
||||
RR->t->tryingNewPath(tPtr,peer->identity(),a,path->address(),pkt.packetId(),Packet::VERB_PUSH_DIRECT_PATHS,peer->address(),peer->identity().hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_RECEIVED_PUSH_DIRECT_PATHS);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case 6: {
|
||||
const InetAddress a(pkt.field(ptr,16),16,pkt.at<uint16_t>(ptr + 16));
|
||||
if (peer->shouldTryPath(tPtr,now,peer,a)) {
|
||||
if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
|
||||
peer->sendHELLO(tPtr,-1,a,now);
|
||||
RR->t->tryingNewPath(tPtr,peer->identity(),a,path->address(),pkt.packetId(),Packet::VERB_PUSH_DIRECT_PATHS,peer->address(),peer->identity().hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_RECEIVED_PUSH_DIRECT_PATHS);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
ptr += addrLen;
|
||||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,0);
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE bool _doUSER_MESSAGE(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
ZT_UserMessage um;
|
||||
int ptr = sizeof(Protocol::Header);
|
||||
um.id = reinterpret_cast<const ZT_Identity *>(&(peer->identity()));
|
||||
um.typeId = p.pkt->rI64(ptr);
|
||||
int ds = (int)p.size - ptr;
|
||||
if (ds > 0) {
|
||||
um.data = p.pkt->data.bytes + ptr;
|
||||
um.length = (unsigned int)ds;
|
||||
RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast<const void *>(&um));
|
||||
}
|
||||
peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_USER_MESSAGE,0,Protocol::VERB_NOP,0);
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
} // anonymous namespace
|
||||
|
||||
bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
||||
{
|
||||
const Address source(pkt->data.fields.source);
|
||||
const SharedPtr<Peer> peer(RR->topology->get(tPtr,source));
|
||||
|
||||
try {
|
||||
// Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear)
|
||||
const uint8_t c = Protocol::packetCipher(pkt->data.fields);
|
||||
bool trusted = false;
|
||||
if (c == ZT_PROTO_CIPHER_SUITE__NONE) {
|
||||
// If this is marked as a packet via a trusted path, check source address and path ID.
|
||||
// Obviously if no trusted paths are configured this always returns false and such
|
||||
// packets are dropped on the floor.
|
||||
const uint64_t tpid = Utils::ntoh(pkt->data.fields.mac); // the MAC is the trusted path ID on these packets
|
||||
if (RR->topology->shouldInboundPathBeTrusted(path->address(),tpid)) {
|
||||
trusted = true;
|
||||
} else {
|
||||
if (peer)
|
||||
RR->t->incomingPacketDropped(tPtr,idBE,0,peer->identity(),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||
return true;
|
||||
}
|
||||
} else if ((c == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)&&(pkt->data.fields.verb == Protocol::VERB_HELLO)) {
|
||||
// Only HELLO is allowed in the clear, but the MAC is still checked in _doHELLO().
|
||||
return _doHELLO(*this,RR,tPtr,false);
|
||||
}
|
||||
|
||||
if (!peer) {
|
||||
RR->sw->requestWhois(tPtr,RR->node->now(),source);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!trusted) {
|
||||
if (!dearmor(peer->key())) {
|
||||
RR->t->incomingPacketDropped(tPtr,idBE,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uncompress()) {
|
||||
RR->t->incomingPacketDropped(tPtr,idBE,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA);
|
||||
return true;
|
||||
}
|
||||
|
||||
const Protocol::Verb verb = (Protocol::Verb)pkt->data.fields.verb;
|
||||
bool r = true;
|
||||
switch(verb) {
|
||||
default: // ignore unknown verbs, but if they pass auth check they are "received" and considered NOPs by peer->receive()
|
||||
RR->t->incomingPacketDropped(tPtr,idBE,0,peer->identity(),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB);
|
||||
// fall through
|
||||
case Protocol::VERB_NOP:
|
||||
peer->received(tPtr,path,hops,idBE,size,Protocol::VERB_NOP,0,Protocol::VERB_NOP,0);
|
||||
break;
|
||||
case Protocol::VERB_HELLO: r = _doHELLO(*this,RR,tPtr,true); break;
|
||||
case Protocol::VERB_ERROR: r = _doERROR(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_OK: r = _doOK(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_WHOIS: r = _doWHOIS(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_RENDEZVOUS: r = _doRENDEZVOUS(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_FRAME: r = _doFRAME(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_EXT_FRAME: r = _doEXT_FRAME(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_ECHO: r = _doECHO(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_NETWORK_CREDENTIALS: r = _doNETWORK_CREDENTIALS(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_NETWORK_CONFIG_REQUEST: r = _doNETWORK_CONFIG_REQUEST(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_NETWORK_CONFIG: r = _doNETWORK_CONFIG(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_MULTICAST_GATHER: r = _doMULTICAST_GATHER(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_PUSH_DIRECT_PATHS: r = _doPUSH_DIRECT_PATHS(*this,RR,tPtr,peer); break;
|
||||
case Protocol::VERB_USER_MESSAGE: r = _doUSER_MESSAGE(*this,RR,tPtr,peer); break;
|
||||
}
|
||||
return r;
|
||||
} catch (int ztExcCode) {
|
||||
} catch ( ... ) {}
|
||||
|
||||
if (peer)
|
||||
RR->t->incomingPacketDropped(tPtr,idBE,0,peer->identity(),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#ifndef ZT_INCOMINGPACKET_HPP
|
||||
#define ZT_INCOMINGPACKET_HPP
|
||||
|
||||
#include "Path.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "MulticastGroup.hpp"
|
||||
#include "Peer.hpp"
|
||||
#include "Buf.hpp"
|
||||
#include "Protocol.hpp"
|
||||
|
||||
/*
|
||||
* The big picture:
|
||||
*
|
||||
* tryDecode gets called for a given fully-assembled packet until it returns
|
||||
* true or the packet's time to live has been exceeded, in which case it is
|
||||
* discarded as failed decode. Any exception thrown by tryDecode also causes
|
||||
* the packet to be discarded.
|
||||
*
|
||||
* Thus a return of false from tryDecode() indicates that it should be called
|
||||
* again. Logic is very simple as to when, and it's in doAnythingWaitingForPeer
|
||||
* in Switch. This might be expanded to be more fine grained in the future.
|
||||
*
|
||||
* A return value of true indicates that the packet is done. tryDecode must
|
||||
* never be called again after that.
|
||||
*/
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
class Network;
|
||||
|
||||
class IncomingPacket
|
||||
{
|
||||
public:
|
||||
ZT_ALWAYS_INLINE IncomingPacket() {}
|
||||
|
||||
template<typename X>
|
||||
ZT_ALWAYS_INLINE void set(const SharedPtr< Buf<X> > &pkt_,const unsigned int pktSize_,const SharedPtr<Path> &path_,const int64_t now_)
|
||||
{
|
||||
idBE = 0; // initially zero, set when decryption/auth occurs
|
||||
receiveTime = now_;
|
||||
path = path_;
|
||||
pkt = reinterpret_cast< SharedPtr< Buf< Protocol::Header > > >(pkt_);
|
||||
size = pktSize_;
|
||||
hops = Protocol::packetHops(pkt->data.fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to decode this packet
|
||||
*
|
||||
* Note that this returns 'true' if processing is complete. This says nothing
|
||||
* about whether the packet was valid. A rejection is 'complete.'
|
||||
*
|
||||
* Once true is returned, this must not be called again. The packet's state
|
||||
* may no longer be valid.
|
||||
*
|
||||
* @param RR Runtime environment
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @return True if decoding and processing is complete, false if caller should try again
|
||||
*/
|
||||
bool tryDecode(const RuntimeEnvironment *RR,void *tPtr);
|
||||
|
||||
/**
|
||||
* Packet ID in big-endian byte order or 0 if not decrypted/dearmored yet
|
||||
*/
|
||||
uint64_t idBE;
|
||||
|
||||
/**
|
||||
* Time packet was received
|
||||
*/
|
||||
int64_t receiveTime;
|
||||
|
||||
/**
|
||||
* Path over which packet was received
|
||||
*/
|
||||
SharedPtr< Path > path;
|
||||
|
||||
/**
|
||||
* Packet itself
|
||||
*/
|
||||
SharedPtr< Buf< Protocol::Header > > pkt;
|
||||
|
||||
/**
|
||||
* Size of packet in bytes
|
||||
*/
|
||||
unsigned int size;
|
||||
|
||||
/**
|
||||
* Hop count for received packet
|
||||
*/
|
||||
uint8_t hops;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
174
attic/MIMC52.cpp
174
attic/MIMC52.cpp
File diff suppressed because one or more lines are too long
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#ifndef ZT_MIMC52_HPP
|
||||
#define ZT_MIMC52_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Compute a number of rounds of the MIMC52 verifiable delay function
|
||||
*
|
||||
* @param salt Input salt
|
||||
* @param saltSize Size of salt in bytes
|
||||
* @param rounds Number of rounds to compute
|
||||
* @return Proof that rounds were computed (proof of CPU cycles spent)
|
||||
*/
|
||||
uint64_t mimc52Delay(const void *salt,unsigned int saltSize,unsigned long rounds);
|
||||
|
||||
/**
|
||||
* Verify a MIMC52 proof of work
|
||||
*
|
||||
* @param salt Original input salt
|
||||
* @param saltSize Size of salt in bytes
|
||||
* @param rounds Number of rounds originally computed
|
||||
* @param proof Proof to verify (most significant 12 bits are ignored)
|
||||
* @return True if proof is valid
|
||||
*/
|
||||
bool mimc52Verify(const void *salt,unsigned int saltSize,unsigned long rounds,uint64_t proof);
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
|
@ -1,558 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#include <netioapi.h>
|
||||
#include <IPHlpApi.h>
|
||||
#endif
|
||||
|
||||
#ifdef __UNIX_LIKE__
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#ifndef ZT_SDK
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
#include <net/if.h>
|
||||
#ifdef __BSD__
|
||||
#include <net/if_dl.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "ManagedRoute.hpp"
|
||||
|
||||
#define ZT_BSD_ROUTE_CMD "/sbin/route"
|
||||
#define ZT_LINUX_IP_COMMAND "/sbin/ip"
|
||||
#define ZT_LINUX_IP_COMMAND_2 "/usr/sbin/ip"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
namespace {
|
||||
|
||||
// Fork a target into two more specific targets e.g. 0.0.0.0/0 -> 0.0.0.0/1, 128.0.0.0/1
|
||||
// If the target is already maximally-specific, 'right' will be unchanged and 'left' will be 't'
|
||||
static void _forkTarget(const InetAddress &t,InetAddress &left,InetAddress &right)
|
||||
{
|
||||
const unsigned int bits = t.netmaskBits() + 1;
|
||||
left = t;
|
||||
if (t.ss_family == AF_INET) {
|
||||
if (bits <= 32) {
|
||||
left.setPort(bits);
|
||||
right = t;
|
||||
reinterpret_cast<struct sockaddr_in *>(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits)));
|
||||
right.setPort(bits);
|
||||
} else {
|
||||
right.zero();
|
||||
}
|
||||
} else if (t.ss_family == AF_INET6) {
|
||||
if (bits <= 128) {
|
||||
left.setPort(bits);
|
||||
right = t;
|
||||
uint8_t *b = reinterpret_cast<uint8_t *>(reinterpret_cast<struct sockaddr_in6 *>(&right)->sin6_addr.s6_addr);
|
||||
b[bits / 8] ^= 1 << (8 - (bits % 8));
|
||||
right.setPort(bits);
|
||||
} else {
|
||||
right.zero();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct _RTE
|
||||
{
|
||||
InetAddress target;
|
||||
InetAddress via;
|
||||
char device[128];
|
||||
int metric;
|
||||
bool ifscope;
|
||||
};
|
||||
|
||||
#ifdef __BSD__ // ------------------------------------------------------------
|
||||
#define ZT_ROUTING_SUPPORT_FOUND 1
|
||||
|
||||
#ifndef ZT_SDK
|
||||
static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
|
||||
{
|
||||
std::vector<_RTE> rtes;
|
||||
int mib[6];
|
||||
size_t needed;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = 0;
|
||||
mib[4] = NET_RT_DUMP;
|
||||
mib[5] = 0;
|
||||
if (!sysctl(mib,6,NULL,&needed,NULL,0)) {
|
||||
if (needed <= 0)
|
||||
return rtes;
|
||||
|
||||
char *buf = (char *)::malloc(needed);
|
||||
if (buf) {
|
||||
if (!sysctl(mib,6,buf,&needed,NULL,0)) {
|
||||
struct rt_msghdr *rtm;
|
||||
for(char *next=buf,*end=buf+needed;next<end;) {
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
char *saptr = (char *)(rtm + 1);
|
||||
char *saend = next + rtm->rtm_msglen;
|
||||
|
||||
InetAddress sa_t,sa_v;
|
||||
int deviceIndex = -9999;
|
||||
|
||||
if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) {
|
||||
int which = 0;
|
||||
while (saptr < saend) {
|
||||
struct sockaddr *sa = (struct sockaddr *)saptr;
|
||||
unsigned int salen = sa->sa_len;
|
||||
if (!salen)
|
||||
break;
|
||||
|
||||
// Skip missing fields in rtm_addrs bit field
|
||||
while ((rtm->rtm_addrs & 1) == 0) {
|
||||
rtm->rtm_addrs >>= 1;
|
||||
++which;
|
||||
if (which > 6)
|
||||
break;
|
||||
}
|
||||
if (which > 6)
|
||||
break;
|
||||
|
||||
rtm->rtm_addrs >>= 1;
|
||||
switch(which++) {
|
||||
case 0:
|
||||
//printf("RTA_DST\n");
|
||||
if (sa->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
|
||||
if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) {
|
||||
// BSD uses this fucking strange in-band signaling method to encode device scope IDs for IPv6 addresses... probably a holdover from very early versions of the spec.
|
||||
unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff);
|
||||
sin6->sin6_addr.s6_addr[2] = 0;
|
||||
sin6->sin6_addr.s6_addr[3] = 0;
|
||||
if (!sin6->sin6_scope_id)
|
||||
sin6->sin6_scope_id = interfaceIndex;
|
||||
}
|
||||
}
|
||||
sa_t = *sa;
|
||||
break;
|
||||
case 1:
|
||||
//printf("RTA_GATEWAY\n");
|
||||
switch(sa->sa_family) {
|
||||
case AF_LINK:
|
||||
deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index;
|
||||
break;
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
sa_v = *sa;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2: {
|
||||
//printf("RTA_NETMASK\n");
|
||||
if (sa_t.ss_family == AF_INET6) {
|
||||
salen = sizeof(struct sockaddr_in6);
|
||||
unsigned int bits = 0;
|
||||
for(int i=0;i<16;++i) {
|
||||
unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i];
|
||||
if (c == 0xff)
|
||||
bits += 8;
|
||||
else break;
|
||||
}
|
||||
sa_t.setPort(bits);
|
||||
} else if (sa_t.ss_family == AF_INET) {
|
||||
salen = sizeof(struct sockaddr_in);
|
||||
sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr));
|
||||
}
|
||||
} break;
|
||||
/*
|
||||
case 3:
|
||||
//printf("RTA_GENMASK\n");
|
||||
break;
|
||||
case 4:
|
||||
//printf("RTA_IFP\n");
|
||||
break;
|
||||
case 5:
|
||||
//printf("RTA_IFA\n");
|
||||
break;
|
||||
case 6:
|
||||
//printf("RTA_AUTHOR\n");
|
||||
break;
|
||||
*/
|
||||
}
|
||||
|
||||
saptr += salen;
|
||||
}
|
||||
|
||||
if (((contains)&&(sa_t.containsAddress(target)))||(sa_t == target)) {
|
||||
rtes.push_back(_RTE());
|
||||
rtes.back().target = sa_t;
|
||||
rtes.back().via = sa_v;
|
||||
if (deviceIndex >= 0) {
|
||||
if_indextoname(deviceIndex,rtes.back().device);
|
||||
} else {
|
||||
rtes.back().device[0] = (char)0;
|
||||
}
|
||||
rtes.back().metric = ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount;
|
||||
}
|
||||
}
|
||||
|
||||
next = saend;
|
||||
}
|
||||
}
|
||||
|
||||
::free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
return rtes;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *ifscope,const char *localInterface)
|
||||
{
|
||||
//char f1[1024],f2[1024]; printf("%s %s %s %s %s\n",op,target.toString(f1),via.toString(f2),ifscope,localInterface);
|
||||
long p = (long)fork();
|
||||
if (p > 0) {
|
||||
int exitcode = -1;
|
||||
::waitpid(p,&exitcode,0);
|
||||
} else if (p == 0) {
|
||||
::close(STDOUT_FILENO);
|
||||
::close(STDERR_FILENO);
|
||||
char ttmp[64];
|
||||
char iptmp[64];
|
||||
if (via) {
|
||||
if ((ifscope)&&(ifscope[0])) {
|
||||
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0);
|
||||
} else {
|
||||
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0);
|
||||
}
|
||||
} else if ((localInterface)&&(localInterface[0])) {
|
||||
if ((ifscope)&&(ifscope[0])) {
|
||||
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0);
|
||||
} else {
|
||||
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0);
|
||||
}
|
||||
}
|
||||
::_exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __BSD__ ------------------------------------------------------------
|
||||
|
||||
#ifdef __LINUX__ // ----------------------------------------------------------
|
||||
#define ZT_ROUTING_SUPPORT_FOUND 1
|
||||
|
||||
static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *localInterface)
|
||||
{
|
||||
long p = (long)fork();
|
||||
if (p > 0) {
|
||||
int exitcode = -1;
|
||||
::waitpid(p,&exitcode,0);
|
||||
} else if (p == 0) {
|
||||
::close(STDOUT_FILENO);
|
||||
::close(STDERR_FILENO);
|
||||
char ipbuf[64],ipbuf2[64];
|
||||
if (via) {
|
||||
::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"via",via.toIpString(ipbuf2),(const char *)0);
|
||||
::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"via",via.toIpString(ipbuf2),(const char *)0);
|
||||
} else if ((localInterface)&&(localInterface[0])) {
|
||||
::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"dev",localInterface,(const char *)0);
|
||||
::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"dev",localInterface,(const char *)0);
|
||||
}
|
||||
::_exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __LINUX__ ----------------------------------------------------------
|
||||
|
||||
#ifdef __WINDOWS__ // --------------------------------------------------------
|
||||
#define ZT_ROUTING_SUPPORT_FOUND 1
|
||||
|
||||
static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &interfaceIndex,const InetAddress &target,const InetAddress &via)
|
||||
{
|
||||
MIB_IPFORWARD_ROW2 rtrow;
|
||||
InitializeIpForwardEntry(&rtrow);
|
||||
rtrow.InterfaceLuid.Value = interfaceLuid.Value;
|
||||
rtrow.InterfaceIndex = interfaceIndex;
|
||||
if (target.ss_family == AF_INET) {
|
||||
rtrow.DestinationPrefix.Prefix.si_family = AF_INET;
|
||||
rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET;
|
||||
rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&target)->sin_addr.S_un.S_addr;
|
||||
if (via.ss_family == AF_INET) {
|
||||
rtrow.NextHop.si_family = AF_INET;
|
||||
rtrow.NextHop.Ipv4.sin_family = AF_INET;
|
||||
rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&via)->sin_addr.S_un.S_addr;
|
||||
}
|
||||
} else if (target.ss_family == AF_INET6) {
|
||||
rtrow.DestinationPrefix.Prefix.si_family = AF_INET6;
|
||||
rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6;
|
||||
memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,reinterpret_cast<const struct sockaddr_in6 *>(&target)->sin6_addr.u.Byte,16);
|
||||
if (via.ss_family == AF_INET6) {
|
||||
rtrow.NextHop.si_family = AF_INET6;
|
||||
rtrow.NextHop.Ipv6.sin6_family = AF_INET6;
|
||||
memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte,reinterpret_cast<const struct sockaddr_in6 *>(&via)->sin6_addr.u.Byte,16);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
rtrow.DestinationPrefix.PrefixLength = target.netmaskBits();
|
||||
rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength;
|
||||
rtrow.ValidLifetime = 0xffffffff;
|
||||
rtrow.PreferredLifetime = 0xffffffff;
|
||||
rtrow.Metric = -1;
|
||||
rtrow.Protocol = MIB_IPPROTO_NETMGMT;
|
||||
rtrow.Loopback = FALSE;
|
||||
rtrow.AutoconfigureAddress = FALSE;
|
||||
rtrow.Publish = FALSE;
|
||||
rtrow.Immortal = FALSE;
|
||||
rtrow.Age = 0;
|
||||
rtrow.Origin = NlroManual;
|
||||
if (del) {
|
||||
return (DeleteIpForwardEntry2(&rtrow) == NO_ERROR);
|
||||
} else {
|
||||
NTSTATUS r = CreateIpForwardEntry2(&rtrow);
|
||||
if (r == NO_ERROR) {
|
||||
return true;
|
||||
} else if (r == ERROR_OBJECT_ALREADY_EXISTS) {
|
||||
return (SetIpForwardEntry2(&rtrow) == NO_ERROR);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool _winHasRoute(const NET_LUID &interfaceLuid, const NET_IFINDEX &interfaceIndex, const InetAddress &target, const InetAddress &via)
|
||||
{
|
||||
MIB_IPFORWARD_ROW2 rtrow;
|
||||
InitializeIpForwardEntry(&rtrow);
|
||||
rtrow.InterfaceLuid.Value = interfaceLuid.Value;
|
||||
rtrow.InterfaceIndex = interfaceIndex;
|
||||
if (target.ss_family == AF_INET) {
|
||||
rtrow.DestinationPrefix.Prefix.si_family = AF_INET;
|
||||
rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET;
|
||||
rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&target)->sin_addr.S_un.S_addr;
|
||||
if (via.ss_family == AF_INET) {
|
||||
rtrow.NextHop.si_family = AF_INET;
|
||||
rtrow.NextHop.Ipv4.sin_family = AF_INET;
|
||||
rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&via)->sin_addr.S_un.S_addr;
|
||||
}
|
||||
} else if (target.ss_family == AF_INET6) {
|
||||
rtrow.DestinationPrefix.Prefix.si_family = AF_INET6;
|
||||
rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6;
|
||||
memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6 *>(&target)->sin6_addr.u.Byte, 16);
|
||||
if (via.ss_family == AF_INET6) {
|
||||
rtrow.NextHop.si_family = AF_INET6;
|
||||
rtrow.NextHop.Ipv6.sin6_family = AF_INET6;
|
||||
memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6 *>(&via)->sin6_addr.u.Byte, 16);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
rtrow.DestinationPrefix.PrefixLength = target.netmaskBits();
|
||||
rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength;
|
||||
return (GetIpForwardEntry2(&rtrow) == NO_ERROR);
|
||||
}
|
||||
|
||||
#endif // __WINDOWS__ --------------------------------------------------------
|
||||
|
||||
#ifndef ZT_ROUTING_SUPPORT_FOUND
|
||||
#error "ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a GitHub pull request if you do this for a new OS."
|
||||
#endif
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/* Linux NOTE: for default route override, some Linux distributions will
|
||||
* require a change to the rp_filter parameter. A value of '1' will prevent
|
||||
* default route override from working properly.
|
||||
*
|
||||
* sudo sysctl -w net.ipv4.conf.all.rp_filter=2
|
||||
*
|
||||
* Add to /etc/sysctl.conf or /etc/sysctl.d/... to make permanent.
|
||||
*
|
||||
* This is true of CentOS/RHEL 6+ and possibly others. This is because
|
||||
* Linux default route override implies asymmetric routes, which then
|
||||
* trigger Linux's "martian packet" filter. */
|
||||
|
||||
#ifndef ZT_SDK
|
||||
bool ManagedRoute::sync()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
NET_LUID interfaceLuid;
|
||||
interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute
|
||||
NET_IFINDEX interfaceIndex = -1;
|
||||
if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
InetAddress leftt,rightt;
|
||||
if (_target.netmaskBits() == 0) // bifurcate only the default route
|
||||
_forkTarget(_target,leftt,rightt);
|
||||
else leftt = _target;
|
||||
|
||||
#ifdef __BSD__ // ------------------------------------------------------------
|
||||
|
||||
// Find lowest metric system route that this route should override (if any)
|
||||
InetAddress newSystemVia;
|
||||
char newSystemDevice[128];
|
||||
newSystemDevice[0] = (char)0;
|
||||
int systemMetric = 9999999;
|
||||
std::vector<_RTE> rtes(_getRTEs(_target,false));
|
||||
for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
|
||||
if (r->via) {
|
||||
if ( ((!newSystemVia)||(r->metric < systemMetric)) && (strcmp(r->device,_device) != 0) ) {
|
||||
newSystemVia = r->via;
|
||||
Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device);
|
||||
systemMetric = r->metric;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get device corresponding to route if we don't have that already
|
||||
if ((newSystemVia)&&(!newSystemDevice[0])) {
|
||||
rtes = _getRTEs(newSystemVia,true);
|
||||
for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
|
||||
if ( (r->device[0]) && (strcmp(r->device,_device) != 0) ) {
|
||||
Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!newSystemDevice[0])
|
||||
newSystemVia.zero();
|
||||
|
||||
// Shadow system route if it exists, also delete any obsolete shadows
|
||||
// and replace them with the new state. sync() is called periodically to
|
||||
// allow us to do that if underlying connectivity changes.
|
||||
if ((_systemVia != newSystemVia)||(strcmp(_systemDevice,newSystemDevice) != 0)) {
|
||||
if (_systemVia) {
|
||||
_routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0);
|
||||
if (rightt)
|
||||
_routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0);
|
||||
}
|
||||
|
||||
_systemVia = newSystemVia;
|
||||
Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice);
|
||||
|
||||
if (_systemVia) {
|
||||
_routeCmd("add",leftt,_systemVia,_systemDevice,(const char *)0);
|
||||
_routeCmd("change",leftt,_systemVia,_systemDevice,(const char *)0);
|
||||
if (rightt) {
|
||||
_routeCmd("add",rightt,_systemVia,_systemDevice,(const char *)0);
|
||||
_routeCmd("change",rightt,_systemVia,_systemDevice,(const char *)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_applied.count(leftt)) {
|
||||
_applied[leftt] = false; // not ifscoped
|
||||
_routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
|
||||
_routeCmd("change",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
|
||||
}
|
||||
if ((rightt)&&(!_applied.count(rightt))) {
|
||||
_applied[rightt] = false; // not ifscoped
|
||||
_routeCmd("add",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
|
||||
_routeCmd("change",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
|
||||
}
|
||||
|
||||
#endif // __BSD__ ------------------------------------------------------------
|
||||
|
||||
#ifdef __LINUX__ // ----------------------------------------------------------
|
||||
|
||||
if (!_applied.count(leftt)) {
|
||||
_applied[leftt] = false; // boolean unused
|
||||
_routeCmd("replace",leftt,_via,(_via) ? (const char *)0 : _device);
|
||||
}
|
||||
if ((rightt)&&(!_applied.count(rightt))) {
|
||||
_applied[rightt] = false; // boolean unused
|
||||
_routeCmd("replace",rightt,_via,(_via) ? (const char *)0 : _device);
|
||||
}
|
||||
|
||||
#endif // __LINUX__ ----------------------------------------------------------
|
||||
|
||||
#ifdef __WINDOWS__ // --------------------------------------------------------
|
||||
|
||||
if ( (!_applied.count(leftt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,leftt,_via)) ) {
|
||||
_applied[leftt] = false; // boolean unused
|
||||
_winRoute(false,interfaceLuid,interfaceIndex,leftt,_via);
|
||||
}
|
||||
if ( (rightt) && ( (!_applied.count(rightt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,rightt,_via)) ) ) {
|
||||
_applied[rightt] = false; // boolean unused
|
||||
_winRoute(false,interfaceLuid,interfaceIndex,rightt,_via);
|
||||
}
|
||||
|
||||
#endif // __WINDOWS__ --------------------------------------------------------
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ManagedRoute::remove()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
NET_LUID interfaceLuid;
|
||||
interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute
|
||||
NET_IFINDEX interfaceIndex = -1;
|
||||
if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef __BSD__
|
||||
if (_systemVia) {
|
||||
InetAddress leftt,rightt;
|
||||
_forkTarget(_target,leftt,rightt);
|
||||
_routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0);
|
||||
if (rightt)
|
||||
_routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0);
|
||||
}
|
||||
#endif // __BSD__ ------------------------------------------------------------
|
||||
|
||||
for(std::map<InetAddress,bool>::iterator r(_applied.begin());r!=_applied.end();++r) {
|
||||
#ifdef __BSD__ // ------------------------------------------------------------
|
||||
_routeCmd("delete",r->first,_via,r->second ? _device : (const char *)0,(_via) ? (const char *)0 : _device);
|
||||
#endif // __BSD__ ------------------------------------------------------------
|
||||
|
||||
#ifdef __LINUX__ // ----------------------------------------------------------
|
||||
_routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device);
|
||||
#endif // __LINUX__ ----------------------------------------------------------
|
||||
|
||||
#ifdef __WINDOWS__ // --------------------------------------------------------
|
||||
_winRoute(true,interfaceLuid,interfaceIndex,r->first,_via);
|
||||
#endif // __WINDOWS__ --------------------------------------------------------
|
||||
}
|
||||
|
||||
_target.zero();
|
||||
_via.zero();
|
||||
_systemVia.zero();
|
||||
_device[0] = (char)0;
|
||||
_systemDevice[0] = (char)0;
|
||||
_applied.clear();
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#ifndef ZT_MANAGEDROUTE_HPP
|
||||
#define ZT_MANAGEDROUTE_HPP
|
||||
|
||||
#include "../node/InetAddress.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/SharedPtr.hpp"
|
||||
#include "../node/Atomic.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* A ZT-managed route that used C++ RAII semantics to automatically clean itself up on deallocate
|
||||
*/
|
||||
class ManagedRoute
|
||||
{
|
||||
friend class SharedPtr<ManagedRoute>;
|
||||
|
||||
public:
|
||||
ZT_INLINE ManagedRoute(const InetAddress &target,const InetAddress &via,const char *device)
|
||||
{
|
||||
_target = target;
|
||||
_via = via;
|
||||
if (via.ss_family == AF_INET)
|
||||
_via.setPort(32);
|
||||
else if (via.ss_family == AF_INET6)
|
||||
_via.setPort(128);
|
||||
Utils::scopy(_device,sizeof(_device),device);
|
||||
_systemDevice[0] = (char)0;
|
||||
}
|
||||
|
||||
ZT_INLINE ~ManagedRoute() { this->remove(); }
|
||||
|
||||
/**
|
||||
* Set or update currently set route
|
||||
*
|
||||
* This must be called periodically for routes that shadow others so that
|
||||
* shadow routes can be updated. In some cases it has no effect
|
||||
*
|
||||
* @return True if route add/update was successful
|
||||
*/
|
||||
bool sync();
|
||||
|
||||
/**
|
||||
* Remove and clear this ManagedRoute
|
||||
*
|
||||
* This does nothing if this ManagedRoute is not set or has already been
|
||||
* removed. If this is not explicitly called it is called automatically on
|
||||
* destruct.
|
||||
*/
|
||||
void remove();
|
||||
|
||||
ZT_INLINE const InetAddress &target() const { return _target; }
|
||||
ZT_INLINE const InetAddress &via() const { return _via; }
|
||||
ZT_INLINE const char *device() const { return _device; }
|
||||
|
||||
private:
|
||||
ZT_INLINE ManagedRoute(const ManagedRoute &) {}
|
||||
ZT_INLINE ManagedRoute &operator=(const ManagedRoute &) { return *this; }
|
||||
|
||||
InetAddress _target;
|
||||
InetAddress _via;
|
||||
InetAddress _systemVia; // for route overrides
|
||||
std::map<InetAddress,bool> _applied; // routes currently applied
|
||||
char _device[128];
|
||||
char _systemDevice[128]; // for route overrides
|
||||
|
||||
Atomic<int> __refCount;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
149
attic/Packet.cpp
149
attic/Packet.cpp
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "Packet.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "LZ4.hpp"
|
||||
|
||||
#if defined(__GCC__) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
|
||||
#define ZT_PACKET_USE_ATOMIC_INTRINSICS
|
||||
#endif
|
||||
#ifndef ZT_PACKET_USE_ATOMIC_INTRINSICS
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
const uint8_t Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
|
||||
|
||||
void Packet::armor(const void *key,bool encryptPayload)
|
||||
{
|
||||
uint8_t mangledKey[32];
|
||||
uint8_t *const data = reinterpret_cast<uint8_t *>(unsafeData());
|
||||
|
||||
// Set flag now, since it affects key mangle function
|
||||
setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__POLY1305_NONE);
|
||||
|
||||
_salsa20MangleKey((const unsigned char *)key,mangledKey);
|
||||
|
||||
Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV);
|
||||
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];
|
||||
poly1305(mac,payload,payloadLen,macKey);
|
||||
memcpy(data + ZT_PACKET_IDX_MAC,mac,8);
|
||||
}
|
||||
|
||||
bool Packet::dearmor(const void *key)
|
||||
{
|
||||
uint8_t mangledKey[32];
|
||||
uint8_t *const data = reinterpret_cast<uint8_t *>(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__POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012)) {
|
||||
_salsa20MangleKey((const unsigned char *)key,mangledKey);
|
||||
Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV);
|
||||
uint64_t macKey[4];
|
||||
s20.crypt12(ZERO_KEY,macKey,sizeof(macKey));
|
||||
uint64_t mac[2];
|
||||
poly1305(mac,payload,payloadLen,macKey);
|
||||
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8))
|
||||
return false;
|
||||
#else
|
||||
if ((*reinterpret_cast<const uint64_t *>(data + ZT_PACKET_IDX_MAC)) != mac[0]) // also secure, constant time
|
||||
return false;
|
||||
#endif
|
||||
if (cs == ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012)
|
||||
s20.crypt12(payload,payload,payloadLen);
|
||||
return true;
|
||||
} else {
|
||||
return false; // unrecognized cipher suite
|
||||
}
|
||||
}
|
||||
|
||||
bool Packet::compress()
|
||||
{
|
||||
char *const data = reinterpret_cast<char *>(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);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Packet::uncompress()
|
||||
{
|
||||
char *const data = reinterpret_cast<char *>(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);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned long long s_initPacketID()
|
||||
{
|
||||
unsigned long long tmp = 0;
|
||||
Utils::getSecureRandom(&tmp,sizeof(tmp));
|
||||
tmp >>= 31U;
|
||||
tmp |= (((uint64_t)time(nullptr)) & 0xffffffffULL) << 33U;
|
||||
return tmp;
|
||||
}
|
||||
#ifdef ZT_PACKET_USE_ATOMIC_INTRINSICS
|
||||
static unsigned long long s_packetIdCtr = s_initPacketID();
|
||||
#else
|
||||
static std::atomic<unsigned long long> s_packetIdCtr(s_initPacketID());
|
||||
#endif
|
||||
|
||||
uint64_t getPacketId()
|
||||
{
|
||||
#ifdef ZT_PACKET_USE_ATOMIC_INTRINSICS
|
||||
return __sync_add_and_fetch(&s_packetIdCtr,1ULL);
|
||||
#else
|
||||
return ++s_packetIdCtr;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
1201
attic/Packet.hpp
1201
attic/Packet.hpp
File diff suppressed because it is too large
Load diff
138
attic/Str.hpp
138
attic/Str.hpp
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#ifndef ZT_STR_HPP
|
||||
#define ZT_STR_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "MAC.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* A short non-allocating replacement for std::string
|
||||
*
|
||||
* @tparam C Maximum capacity (default: 1021 to make total size 1024)
|
||||
*/
|
||||
template<unsigned long C = 1021>
|
||||
class Str
|
||||
{
|
||||
public:
|
||||
typedef char * iterator;
|
||||
typedef const char * const_iterator;
|
||||
|
||||
ZT_ALWAYS_INLINE Str() { memset(reinterpret_cast<void *>(this),0,sizeof(Str)); }
|
||||
explicit ZT_ALWAYS_INLINE Str(const char *s) { *this = s; }
|
||||
|
||||
ZT_ALWAYS_INLINE Str &operator=(const char *s)
|
||||
{
|
||||
if (s) {
|
||||
unsigned int l = 0;
|
||||
while (l < C) {
|
||||
char c = s[l];
|
||||
if (!c) break;
|
||||
_s[l++] = c;
|
||||
}
|
||||
_s[l] = 0;
|
||||
_l = (uint16_t)l;
|
||||
} else {
|
||||
_l = 0;
|
||||
_s[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE char operator[](const unsigned int i) const
|
||||
{
|
||||
if (i >= (unsigned int)_l)
|
||||
return 0;
|
||||
return _s[i];
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE void clear() { _l = 0; _s[0] = 0; }
|
||||
ZT_ALWAYS_INLINE const char *c_str() const { return _s; }
|
||||
ZT_ALWAYS_INLINE unsigned int length() const { return (unsigned int)_l; }
|
||||
ZT_ALWAYS_INLINE bool empty() const { return (_l == 0); }
|
||||
|
||||
ZT_ALWAYS_INLINE iterator begin() { return (iterator)_s; }
|
||||
ZT_ALWAYS_INLINE iterator end() { return (iterator)(_s + (unsigned long)_l); }
|
||||
ZT_ALWAYS_INLINE const_iterator begin() const { return (const_iterator)_s; }
|
||||
ZT_ALWAYS_INLINE const_iterator end() const { return (const_iterator)(_s + (unsigned long)_l); }
|
||||
|
||||
ZT_ALWAYS_INLINE Str &operator<<(const char *s)
|
||||
{
|
||||
if (s) {
|
||||
unsigned int l = _l;
|
||||
while (l < C) {
|
||||
char c = s[l];
|
||||
if (!c) break;
|
||||
_s[l++] = c;
|
||||
}
|
||||
_s[l] = 0;
|
||||
_l = (uint16_t)l;
|
||||
}
|
||||
}
|
||||
ZT_ALWAYS_INLINE Str &operator<<(const Str &s) { return ((*this) << s._s); }
|
||||
ZT_ALWAYS_INLINE Str &operator<<(const char c)
|
||||
{
|
||||
if (_l < C) {
|
||||
_s[_l++] = c;
|
||||
_s[_l] = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE Str &operator<<(const Address &a)
|
||||
{
|
||||
char tmp[32];
|
||||
return ((*this) << a.toString(tmp));
|
||||
}
|
||||
ZT_ALWAYS_INLINE Str &operator<<(const InetAddress &a)
|
||||
{
|
||||
char tmp[128];
|
||||
return ((*this) << a.toString(tmp));
|
||||
}
|
||||
ZT_ALWAYS_INLINE Str &operator<<(const MAC &a)
|
||||
{
|
||||
char tmp[64];
|
||||
return ((*this) << a.toString(tmp));
|
||||
}
|
||||
|
||||
ZT_ALWAYS_INLINE operator bool() const { return (_l != 0); }
|
||||
|
||||
ZT_ALWAYS_INLINE bool operator==(const Str &s) const { return ((_l == s._l)&&(memcmp(_s,s._s,_l) == 0)); }
|
||||
ZT_ALWAYS_INLINE bool operator!=(const Str &s) const { return ((_l != s._l)||(memcmp(_s,s._s,_l) != 0)); }
|
||||
ZT_ALWAYS_INLINE bool operator<(const Str &s) const { return ( (_l < s._l) ? true : ((_l == s._l) ? (memcmp(_s,s._s,_l) < 0) : false) ); }
|
||||
ZT_ALWAYS_INLINE bool operator>(const Str &s) const { return (s < *this); }
|
||||
ZT_ALWAYS_INLINE bool operator<=(const Str &s) const { return !(s < *this); }
|
||||
ZT_ALWAYS_INLINE bool operator>=(const Str &s) const { return !(*this < s); }
|
||||
|
||||
ZT_ALWAYS_INLINE bool operator==(const char *s) const { return (strcmp(_s,s) == 0); }
|
||||
ZT_ALWAYS_INLINE bool operator!=(const char *s) const { return (strcmp(_s,s) != 0); }
|
||||
ZT_ALWAYS_INLINE bool operator<(const char *s) const { return (strcmp(_s,s) < 0); }
|
||||
ZT_ALWAYS_INLINE bool operator>(const char *s) const { return (strcmp(_s,s) > 0); }
|
||||
ZT_ALWAYS_INLINE bool operator<=(const char *s) const { return (strcmp(_s,s) <= 0); }
|
||||
ZT_ALWAYS_INLINE bool operator>=(const char *s) const { return (strcmp(_s,s) >= 0); }
|
||||
|
||||
ZT_ALWAYS_INLINE unsigned long hashCode() const { return Utils::hashString(_s,_l); }
|
||||
|
||||
private:
|
||||
uint16_t _l;
|
||||
char _s[C+1];
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
630
attic/Switch.cpp
630
attic/Switch.cpp
|
@ -1,630 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Switch.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "Peer.hpp"
|
||||
#include "SelfAwareness.hpp"
|
||||
#include "Trace.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
Switch::Switch(const RuntimeEnvironment *renv) :
|
||||
RR(renv),
|
||||
_lastCheckedQueues(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len)
|
||||
{
|
||||
try {
|
||||
const int64_t now = RR->node->now();
|
||||
|
||||
const SharedPtr<Path> path(RR->topology->getPath(localSocket,fromAddr));
|
||||
path->received(now);
|
||||
|
||||
if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) { // SECURITY: min length check is important since we do some C-style stuff below!
|
||||
if (reinterpret_cast<const uint8_t *>(data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) {
|
||||
// Handle fragment ----------------------------------------------------
|
||||
|
||||
Packet::Fragment fragment(data,len);
|
||||
const Address destination(fragment.destination());
|
||||
|
||||
if (destination != RR->identity.address()) {
|
||||
if (fragment.hops() < ZT_RELAY_MAX_HOPS) {
|
||||
fragment.incrementHops();
|
||||
SharedPtr<Peer> relayTo = RR->topology->get(tPtr,destination);
|
||||
if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now))) {
|
||||
relayTo = RR->topology->root();
|
||||
if (relayTo)
|
||||
relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fragment looks like ours
|
||||
const uint64_t fragmentPacketId = fragment.packetId();
|
||||
const unsigned int fragmentNumber = fragment.fragmentNumber();
|
||||
const unsigned int totalFragments = fragment.totalFragments();
|
||||
|
||||
if ((totalFragments <= ZT_MAX_PACKET_FRAGMENTS)&&(fragmentNumber < ZT_MAX_PACKET_FRAGMENTS)&&(fragmentNumber > 0)&&(totalFragments > 1)) {
|
||||
// Fragment appears basically sane. Its fragment number must be
|
||||
// 1 or more, since a Packet with fragmented bit set is fragment 0.
|
||||
// Total fragments must be more than 1, otherwise why are we
|
||||
// seeing a Packet::Fragment?
|
||||
|
||||
RXQueueEntry *const rq = _findRXQueueEntry(fragmentPacketId);
|
||||
Mutex::Lock rql(rq->lock);
|
||||
if (rq->packetId != fragmentPacketId) {
|
||||
// No packet found, so we received a fragment without its head.
|
||||
|
||||
rq->timestamp = now;
|
||||
rq->packetId = fragmentPacketId;
|
||||
rq->frags[fragmentNumber - 1] = fragment;
|
||||
rq->totalFragments = totalFragments; // total fragment count is known
|
||||
rq->haveFragments = 1 << fragmentNumber; // we have only this fragment
|
||||
rq->complete = false;
|
||||
} else if (!(rq->haveFragments & (1 << fragmentNumber))) {
|
||||
// We have other fragments and maybe the head, so add this one and check
|
||||
|
||||
rq->frags[fragmentNumber - 1] = fragment;
|
||||
rq->totalFragments = totalFragments;
|
||||
|
||||
if (Utils::countBits(rq->haveFragments |= (1 << fragmentNumber)) == totalFragments) {
|
||||
// We have all fragments -- assemble and process full Packet
|
||||
|
||||
for(unsigned int f=1;f<totalFragments;++f)
|
||||
rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength());
|
||||
|
||||
if (rq->frag0.tryDecode(RR,tPtr)) {
|
||||
rq->timestamp = 0; // packet decoded, free entry
|
||||
} else {
|
||||
rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something
|
||||
}
|
||||
}
|
||||
} // else this is a duplicate fragment, ignore
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
} else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) { // min length check is important!
|
||||
// Handle packet head -------------------------------------------------
|
||||
|
||||
const Address destination(reinterpret_cast<const uint8_t *>(data) + 8,ZT_ADDRESS_LENGTH);
|
||||
const Address source(reinterpret_cast<const uint8_t *>(data) + 13,ZT_ADDRESS_LENGTH);
|
||||
|
||||
if (source == RR->identity.address())
|
||||
return;
|
||||
|
||||
if (destination != RR->identity.address()) {
|
||||
// This packet is not for this node, so possibly relay it ----------
|
||||
|
||||
Packet packet(data,len);
|
||||
if (packet.hops() < ZT_RELAY_MAX_HOPS) {
|
||||
packet.incrementHops();
|
||||
SharedPtr<Peer> relayTo = RR->topology->get(tPtr,destination);
|
||||
if ((!relayTo)||(!relayTo->sendDirect(tPtr,packet.data(),packet.size(),now))) {
|
||||
relayTo = RR->topology->root();
|
||||
if ((relayTo)&&(relayTo->address() != source))
|
||||
relayTo->sendDirect(tPtr,packet.data(),packet.size(),now);
|
||||
}
|
||||
}
|
||||
|
||||
} else if ((reinterpret_cast<const uint8_t *>(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) {
|
||||
// Packet is the head of a fragmented packet series ----------------
|
||||
|
||||
const uint64_t packetId = (
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[0]) << 56U) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[1]) << 48U) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[2]) << 40U) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[3]) << 32U) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[4]) << 24U) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[5]) << 16U) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[6]) << 8U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(data)[7])
|
||||
);
|
||||
|
||||
RXQueueEntry *const rq = _findRXQueueEntry(packetId);
|
||||
Mutex::Lock rql(rq->lock);
|
||||
if (rq->packetId != packetId) {
|
||||
// If we have no other fragments yet, create an entry and save the head
|
||||
|
||||
rq->timestamp = now;
|
||||
rq->packetId = packetId;
|
||||
rq->frag0.init(data,len,path,now);
|
||||
rq->totalFragments = 0;
|
||||
rq->haveFragments = 1;
|
||||
rq->complete = false;
|
||||
} else if (!(rq->haveFragments & 1)) {
|
||||
// Check if packet is complete -----------------------------------
|
||||
|
||||
if ((rq->totalFragments > 1)&&(Utils::countBits(rq->haveFragments |= 1) == rq->totalFragments)) {
|
||||
// We have all fragments -- assemble and process full Packet ---
|
||||
|
||||
rq->frag0.init(data,len,path,now);
|
||||
for(unsigned int f=1;f<rq->totalFragments;++f)
|
||||
rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength());
|
||||
|
||||
if (rq->frag0.tryDecode(RR,tPtr)) {
|
||||
rq->timestamp = 0; // packet decoded, free entry
|
||||
} else {
|
||||
rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something
|
||||
}
|
||||
|
||||
} else {
|
||||
// Still waiting on more fragments, but keep the head ----------
|
||||
|
||||
rq->frag0.init(data,len,path,now);
|
||||
|
||||
}
|
||||
} // else this is a duplicate head, ignore
|
||||
} else {
|
||||
|
||||
// Packet is unfragmented, so just process it ----------------------
|
||||
IncomingPacket packet(data,len,path,now);
|
||||
if (!packet.tryDecode(RR,tPtr)) {
|
||||
RXQueueEntry *const rq = _nextRXQueueEntry();
|
||||
Mutex::Lock rql(rq->lock);
|
||||
rq->timestamp = now;
|
||||
rq->packetId = packet.packetId();
|
||||
rq->frag0 = packet;
|
||||
rq->totalFragments = 1;
|
||||
rq->haveFragments = 1;
|
||||
rq->complete = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {} // sanity check, should be caught elsewhere
|
||||
}
|
||||
|
||||
void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
|
||||
{
|
||||
if (!network->hasConfig())
|
||||
return;
|
||||
|
||||
// Check if this packet is from someone other than the tap -- i.e. bridged in
|
||||
bool fromBridged;
|
||||
if ((fromBridged = (from != network->mac()))) {
|
||||
if (!network->config().permitsBridging(RR->identity.address())) {
|
||||
RR->t->outgoingNetworkFrameDropped(tPtr,network->id(),from,to,(uint16_t)etherType,(uint16_t)len,(const uint8_t *)data,ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t qosBucket = 0;
|
||||
|
||||
if (to.isMulticast()) {
|
||||
MulticastGroup multicastGroup(to,0);
|
||||
|
||||
if (to.isBroadcast()) {
|
||||
if ( (etherType == ZT_ETHERTYPE_ARP) && (len >= 28) && ((((const uint8_t *)data)[2] == 0x08)&&(((const uint8_t *)data)[3] == 0x00)&&(((const uint8_t *)data)[4] == 6)&&(((const uint8_t *)data)[5] == 4)&&(((const uint8_t *)data)[7] == 0x01)) ) {
|
||||
/* IPv4 ARP is one of the few special cases that we impose upon what is
|
||||
* otherwise a straightforward Ethernet switch emulation. Vanilla ARP
|
||||
* is dumb old broadcast and simply doesn't scale. ZeroTier multicast
|
||||
* groups have an additional field called ADI (additional distinguishing
|
||||
* information) which was added specifically for ARP though it could
|
||||
* be used for other things too. We then take ARP broadcasts and turn
|
||||
* them into multicasts by stuffing the IP address being queried into
|
||||
* the 32-bit ADI field. In practice this uses our multicast pub/sub
|
||||
* system to implement a kind of extended/distributed ARP table. */
|
||||
multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0));
|
||||
} else if (!network->config().enableBroadcast()) {
|
||||
// Don't transmit broadcasts if this network doesn't want them
|
||||
RR->t->outgoingNetworkFrameDropped(tPtr,network->id(),from,to,(uint16_t)etherType,(uint16_t)len,(const uint8_t *)data,ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED);
|
||||
return;
|
||||
}
|
||||
} else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) {
|
||||
// IPv6 NDP emulation for certain very special patterns of private IPv6 addresses -- if enabled
|
||||
if ((network->config().ndpEmulation())&&(reinterpret_cast<const uint8_t *>(data)[6] == 0x3a)&&(reinterpret_cast<const uint8_t *>(data)[40] == 0x87)) { // ICMPv6 neighbor solicitation
|
||||
Address v6EmbeddedAddress;
|
||||
const uint8_t *const pkt6 = reinterpret_cast<const uint8_t *>(data) + 40 + 8;
|
||||
const uint8_t *my6 = (const uint8_t *)0;
|
||||
|
||||
// ZT-RFC4193 address: fdNN:NNNN:NNNN:NNNN:NN99:93DD:DDDD:DDDD / 88 (one /128 per actual host)
|
||||
|
||||
// ZT-6PLANE address: fcXX:XXXX:XXDD:DDDD:DDDD:####:####:#### / 40 (one /80 per actual host)
|
||||
// (XX - lower 32 bits of network ID XORed with higher 32 bits)
|
||||
|
||||
// For these to work, we must have a ZT-managed address assigned in one of the
|
||||
// above formats, and the query must match its prefix.
|
||||
for(unsigned int sipk=0;sipk<network->config().staticIpCount;++sipk) {
|
||||
const InetAddress *const sip = &(network->config().staticIps[sipk]);
|
||||
if (sip->ss_family == AF_INET6) {
|
||||
my6 = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&(*sip))->sin6_addr.s6_addr);
|
||||
const unsigned int sipNetmaskBits = Utils::ntoh((uint16_t)reinterpret_cast<const struct sockaddr_in6 *>(&(*sip))->sin6_port);
|
||||
if ((sipNetmaskBits == 88)&&(my6[0] == 0xfd)&&(my6[9] == 0x99)&&(my6[10] == 0x93)) { // ZT-RFC4193 /88 ???
|
||||
unsigned int ptr = 0;
|
||||
while (ptr != 11) {
|
||||
if (pkt6[ptr] != my6[ptr])
|
||||
break;
|
||||
++ptr;
|
||||
}
|
||||
if (ptr == 11) { // prefix match!
|
||||
v6EmbeddedAddress.setTo(pkt6 + ptr,5);
|
||||
break;
|
||||
}
|
||||
} else if (sipNetmaskBits == 40) { // ZT-6PLANE /40 ???
|
||||
const uint32_t nwid32 = (uint32_t)((network->id() ^ (network->id() >> 32U)) & 0xffffffffU);
|
||||
if ( (my6[0] == 0xfc) && (my6[1] == (uint8_t)((nwid32 >> 24U) & 0xffU)) && (my6[2] == (uint8_t)((nwid32 >> 16U) & 0xffU)) && (my6[3] == (uint8_t)((nwid32 >> 8U) & 0xffU)) && (my6[4] == (uint8_t)(nwid32 & 0xffU))) {
|
||||
unsigned int ptr = 0;
|
||||
while (ptr != 5) {
|
||||
if (pkt6[ptr] != my6[ptr])
|
||||
break;
|
||||
++ptr;
|
||||
}
|
||||
if (ptr == 5) { // prefix match!
|
||||
v6EmbeddedAddress.setTo(pkt6 + ptr,5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((v6EmbeddedAddress)&&(v6EmbeddedAddress != RR->identity.address())) {
|
||||
const MAC peerMac(v6EmbeddedAddress,network->id());
|
||||
|
||||
uint8_t adv[72];
|
||||
adv[0] = 0x60; adv[1] = 0x00; adv[2] = 0x00; adv[3] = 0x00;
|
||||
adv[4] = 0x00; adv[5] = 0x20;
|
||||
adv[6] = 0x3a; adv[7] = 0xff;
|
||||
for(int i=0;i<16;++i) adv[8 + i] = pkt6[i];
|
||||
for(int i=0;i<16;++i) adv[24 + i] = my6[i];
|
||||
adv[40] = 0x88; adv[41] = 0x00;
|
||||
adv[42] = 0x00; adv[43] = 0x00; // future home of checksum
|
||||
adv[44] = 0x60; adv[45] = 0x00; adv[46] = 0x00; adv[47] = 0x00;
|
||||
for(int i=0;i<16;++i) adv[48 + i] = pkt6[i];
|
||||
adv[64] = 0x02; adv[65] = 0x01;
|
||||
adv[66] = peerMac[0]; adv[67] = peerMac[1]; adv[68] = peerMac[2]; adv[69] = peerMac[3]; adv[70] = peerMac[4]; adv[71] = peerMac[5];
|
||||
|
||||
uint16_t pseudo_[36];
|
||||
uint8_t *const pseudo = reinterpret_cast<uint8_t *>(pseudo_);
|
||||
for(int i=0;i<32;++i) pseudo[i] = adv[8 + i];
|
||||
pseudo[32] = 0x00; pseudo[33] = 0x00; pseudo[34] = 0x00; pseudo[35] = 0x20;
|
||||
pseudo[36] = 0x00; pseudo[37] = 0x00; pseudo[38] = 0x00; pseudo[39] = 0x3a;
|
||||
for(int i=0;i<32;++i) pseudo[40 + i] = adv[40 + i];
|
||||
uint32_t checksum = 0;
|
||||
for(int i=0;i<36;++i) checksum += Utils::hton(pseudo_[i]);
|
||||
while ((checksum >> 16U)) checksum = (checksum & 0xffffU) + (checksum >> 16U);
|
||||
checksum = ~checksum;
|
||||
adv[42] = (checksum >> 8U) & 0xffU;
|
||||
adv[43] = checksum & 0xffU;
|
||||
|
||||
RR->node->putFrame(tPtr,network->id(),network->userPtr(),peerMac,from,ZT_ETHERTYPE_IPV6,0,adv,72);
|
||||
return; // NDP emulation done. We have forged a "fake" reply, so no need to send actual NDP query.
|
||||
} // else no NDP emulation
|
||||
} // else no NDP emulation
|
||||
}
|
||||
|
||||
// Check this after NDP emulation, since that has to be allowed in exactly this case
|
||||
if (network->config().multicastLimit == 0) {
|
||||
RR->t->outgoingNetworkFrameDropped(tPtr,network->id(),from,to,(uint16_t)etherType,(uint16_t)len,(const uint8_t *)data,ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Learn multicast groups for bridged-in hosts.
|
||||
* Note that some OSes, most notably Linux, do this for you by learning
|
||||
* multicast addresses on bridge interfaces and subscribing each slave.
|
||||
* But in that case this does no harm, as the sets are just merged. */
|
||||
if (fromBridged)
|
||||
network->learnBridgedMulticastGroup(tPtr,multicastGroup,RR->node->now());
|
||||
|
||||
// First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates.
|
||||
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
|
||||
RR->t->outgoingNetworkFrameDropped(tPtr,network->id(),from,to,(uint16_t)etherType,(uint16_t)len,(const uint8_t *)data,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO
|
||||
/*
|
||||
RR->mc->send(
|
||||
tPtr,
|
||||
RR->node->now(),
|
||||
network,
|
||||
Address(),
|
||||
multicastGroup,
|
||||
(fromBridged) ? from : MAC(),
|
||||
etherType,
|
||||
data,
|
||||
len);
|
||||
*/
|
||||
} else if (to == network->mac()) {
|
||||
// Destination is this node, so just reinject it -------------------------
|
||||
|
||||
RR->node->putFrame(tPtr,network->id(),network->userPtr(),from,to,etherType,vlanId,data,len);
|
||||
|
||||
} else if (to[0] == MAC::firstOctetForNetwork(network->id())) {
|
||||
// Destination is another ZeroTier peer on the same network --------------
|
||||
|
||||
Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this
|
||||
SharedPtr<Peer> toPeer(RR->topology->get(tPtr,toZT));
|
||||
|
||||
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
|
||||
RR->t->outgoingNetworkFrameDropped(tPtr,network->id(),from,to,(uint16_t)etherType,(uint16_t)len,(const uint8_t *)data,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED);
|
||||
return;
|
||||
}
|
||||
|
||||
network->pushCredentialsIfNeeded(tPtr,toZT,RR->node->now());
|
||||
|
||||
if (fromBridged) {
|
||||
Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME);
|
||||
outp.append(network->id());
|
||||
outp.append((unsigned char)0x00);
|
||||
to.appendTo(outp);
|
||||
from.appendTo(outp);
|
||||
outp.append((uint16_t)etherType);
|
||||
outp.append(data,len);
|
||||
} else {
|
||||
Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME);
|
||||
outp.append(network->id());
|
||||
outp.append((uint16_t)etherType);
|
||||
outp.append(data,len);
|
||||
}
|
||||
} else {
|
||||
// Destination is bridged behind a remote peer ---------------------------
|
||||
|
||||
// We filter with a NULL destination ZeroTier address first. Filtrations
|
||||
// for each ZT destination are also done below. This is the same rationale
|
||||
// and design as for multicast.
|
||||
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
|
||||
RR->t->outgoingNetworkFrameDropped(tPtr,network->id(),from,to,(uint16_t)etherType,(uint16_t)len,(const uint8_t *)data,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED);
|
||||
return;
|
||||
}
|
||||
|
||||
Address bridges[ZT_MAX_BRIDGE_SPAM];
|
||||
unsigned int numBridges = 0;
|
||||
|
||||
/* Create an array of up to ZT_MAX_BRIDGE_SPAM recipients for this bridged frame. */
|
||||
bridges[0] = network->findBridgeTo(to);
|
||||
std::vector<Address> activeBridges;
|
||||
for(unsigned int i=0;i<network->config().specialistCount;++i) {
|
||||
if ((network->config().specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)
|
||||
activeBridges.push_back(Address(network->config().specialists[i]));
|
||||
}
|
||||
if ((bridges[0])&&(bridges[0] != RR->identity.address())&&(network->config().permitsBridging(bridges[0]))) {
|
||||
/* We have a known bridge route for this MAC, send it there. */
|
||||
++numBridges;
|
||||
} else if (!activeBridges.empty()) {
|
||||
/* If there is no known route, spam to up to ZT_MAX_BRIDGE_SPAM active
|
||||
* bridges. If someone responds, we'll learn the route. */
|
||||
std::vector<Address>::const_iterator ab(activeBridges.begin());
|
||||
if (activeBridges.size() <= ZT_MAX_BRIDGE_SPAM) {
|
||||
// If there are <= ZT_MAX_BRIDGE_SPAM active bridges, spam them all
|
||||
while (ab != activeBridges.end()) {
|
||||
bridges[numBridges++] = *ab;
|
||||
++ab;
|
||||
}
|
||||
} else {
|
||||
// Otherwise pick a random set of them
|
||||
while (numBridges < ZT_MAX_BRIDGE_SPAM) {
|
||||
if (ab == activeBridges.end())
|
||||
ab = activeBridges.begin();
|
||||
if (((unsigned long)Utils::random() % (unsigned long)activeBridges.size()) == 0) {
|
||||
bridges[numBridges++] = *ab;
|
||||
++ab;
|
||||
} else ++ab;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int b=0;b<numBridges;++b) {
|
||||
if (network->filterOutgoingPacket(tPtr,true,RR->identity.address(),bridges[b],from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
|
||||
Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME);
|
||||
outp.append(network->id());
|
||||
outp.append((uint8_t)0x00);
|
||||
to.appendTo(outp);
|
||||
from.appendTo(outp);
|
||||
outp.append((uint16_t)etherType);
|
||||
outp.append(data,len);
|
||||
} else {
|
||||
RR->t->outgoingNetworkFrameDropped(tPtr,network->id(),from,to,(uint16_t)etherType,(uint16_t)len,(const uint8_t *)data,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Switch::send(void *tPtr,Packet &packet,bool encrypt)
|
||||
{
|
||||
const Address dest(packet.destination());
|
||||
if (dest == RR->identity.address())
|
||||
return;
|
||||
if (!_trySend(tPtr,packet,encrypt)) {
|
||||
{
|
||||
Mutex::Lock _l(_txQueue_m);
|
||||
if (_txQueue.size() >= ZT_TX_QUEUE_SIZE) {
|
||||
_txQueue.pop_front();
|
||||
}
|
||||
_txQueue.push_back(TXQueueEntry(dest,RR->node->now(),packet,encrypt));
|
||||
}
|
||||
if (!RR->topology->get(tPtr,dest))
|
||||
requestWhois(tPtr,RR->node->now(),dest);
|
||||
}
|
||||
}
|
||||
|
||||
void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr)
|
||||
{
|
||||
if (addr == RR->identity.address())
|
||||
return;
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_lastSentWhoisRequest_m);
|
||||
int64_t &last = _lastSentWhoisRequest[addr];
|
||||
if ((now - last) < ZT_WHOIS_RETRY_DELAY)
|
||||
return;
|
||||
else last = now;
|
||||
}
|
||||
|
||||
const SharedPtr<Peer> root(RR->topology->root());
|
||||
if (root) {
|
||||
Packet outp(root->address(),RR->identity.address(),Packet::VERB_WHOIS);
|
||||
addr.appendTo(outp);
|
||||
RR->node->expectReplyTo(outp.packetId());
|
||||
root->sendDirect(tPtr,outp.data(),outp.size(),now);
|
||||
}
|
||||
}
|
||||
|
||||
void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
{
|
||||
Mutex::Lock _l(_lastSentWhoisRequest_m);
|
||||
_lastSentWhoisRequest.erase(peer->address());
|
||||
}
|
||||
|
||||
const int64_t now = RR->node->now();
|
||||
for(unsigned int ptr=0;ptr<ZT_RX_QUEUE_SIZE;++ptr) {
|
||||
RXQueueEntry *const rq = &(_rxQueue[ptr]);
|
||||
Mutex::Lock rql(rq->lock);
|
||||
if ((rq->timestamp)&&(rq->complete)) {
|
||||
if ((rq->frag0.tryDecode(RR,tPtr))||((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT))
|
||||
rq->timestamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_txQueue_m);
|
||||
for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) {
|
||||
if (txi->dest == peer->address()) {
|
||||
if (_trySend(tPtr,txi->packet,txi->encrypt)) {
|
||||
_txQueue.erase(txi++);
|
||||
} else {
|
||||
++txi;
|
||||
}
|
||||
} else {
|
||||
++txi;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
|
||||
{
|
||||
const uint64_t timeSinceLastCheck = now - _lastCheckedQueues;
|
||||
if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY)
|
||||
return (unsigned long)(ZT_WHOIS_RETRY_DELAY - timeSinceLastCheck);
|
||||
_lastCheckedQueues = now;
|
||||
|
||||
std::vector<Address> needWhois;
|
||||
{
|
||||
Mutex::Lock _l(_txQueue_m);
|
||||
|
||||
for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) {
|
||||
if (_trySend(tPtr,txi->packet,txi->encrypt)) {
|
||||
_txQueue.erase(txi++);
|
||||
} else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) {
|
||||
_txQueue.erase(txi++);
|
||||
} else {
|
||||
if (!RR->topology->get(tPtr,txi->dest))
|
||||
needWhois.push_back(txi->dest);
|
||||
++txi;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(std::vector<Address>::const_iterator i(needWhois.begin());i!=needWhois.end();++i)
|
||||
requestWhois(tPtr,now,*i);
|
||||
|
||||
for(unsigned int ptr=0;ptr<ZT_RX_QUEUE_SIZE;++ptr) {
|
||||
RXQueueEntry *const rq = &(_rxQueue[ptr]);
|
||||
Mutex::Lock rql(rq->lock);
|
||||
if ((rq->timestamp)&&(rq->complete)) {
|
||||
if ((rq->frag0.tryDecode(RR,tPtr))||((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT)) {
|
||||
rq->timestamp = 0;
|
||||
} else {
|
||||
const Address src(rq->frag0.source());
|
||||
if (!RR->topology->get(tPtr,src))
|
||||
requestWhois(tPtr,now,src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_lastSentWhoisRequest_m);
|
||||
Hashtable< Address,int64_t >::Iterator i(_lastSentWhoisRequest);
|
||||
Address *a = (Address *)0;
|
||||
int64_t *ts = (int64_t *)0;
|
||||
while (i.next(a,ts)) {
|
||||
if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2))
|
||||
_lastSentWhoisRequest.erase(*a);
|
||||
}
|
||||
}
|
||||
|
||||
return ZT_WHOIS_RETRY_DELAY;
|
||||
}
|
||||
|
||||
bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt)
|
||||
{
|
||||
const int64_t now = RR->node->now();
|
||||
const SharedPtr<Peer> peer(RR->topology->get(tPtr,packet.destination()));
|
||||
SharedPtr<Path> viaPath;
|
||||
if (peer) {
|
||||
viaPath = peer->path(now);
|
||||
if (!viaPath) {
|
||||
const SharedPtr<Peer> relay(RR->topology->root());
|
||||
if (relay) {
|
||||
viaPath = relay->path(now);
|
||||
if (!viaPath)
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int mtu = ZT_DEFAULT_PHYSMTU;
|
||||
uint64_t trustedPathId = 0;
|
||||
RR->topology->getOutboundPathInfo(viaPath->address(),mtu,trustedPathId);
|
||||
|
||||
unsigned int chunkSize = std::min(packet.size(),mtu);
|
||||
packet.setFragmented(chunkSize < packet.size());
|
||||
|
||||
if (trustedPathId) {
|
||||
packet.setTrusted(trustedPathId);
|
||||
} else {
|
||||
packet.armor(peer->key(),encrypt);
|
||||
}
|
||||
|
||||
if (viaPath->send(RR,tPtr,packet.data(),chunkSize,now)) {
|
||||
if (chunkSize < packet.size()) {
|
||||
// Too big for one packet, fragment the rest
|
||||
unsigned int fragStart = chunkSize;
|
||||
unsigned int remaining = packet.size() - chunkSize;
|
||||
unsigned int fragsRemaining = (remaining / (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH));
|
||||
if ((fragsRemaining * (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining)
|
||||
++fragsRemaining;
|
||||
const unsigned int totalFragments = fragsRemaining + 1;
|
||||
|
||||
for(unsigned int fno=1;fno<totalFragments;++fno) {
|
||||
chunkSize = std::min(remaining,(unsigned int)(mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH));
|
||||
Packet::Fragment frag(packet,fragStart,chunkSize,fno,totalFragments);
|
||||
viaPath->send(RR,tPtr,frag.data(),frag.size(),now);
|
||||
fragStart += chunkSize;
|
||||
remaining -= chunkSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
192
attic/Switch.hpp
192
attic/Switch.hpp
|
@ -1,192 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#ifndef ZT_N_SWITCH_HPP
|
||||
#define ZT_N_SWITCH_HPP
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "MAC.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Network.hpp"
|
||||
#include "SharedPtr.hpp"
|
||||
#include "IncomingPacket.hpp"
|
||||
#include "Hashtable.hpp"
|
||||
#include "Protocol.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
class Peer;
|
||||
|
||||
/**
|
||||
* Core of the distributed Ethernet switch and protocol implementation
|
||||
*
|
||||
* This class is perhaps a bit misnamed, but it's basically where everything
|
||||
* meets. Transport-layer ZT packets come in here, as do virtual network
|
||||
* packets from tap devices, and this sends them where they need to go and
|
||||
* wraps/unwraps accordingly. It also handles queues and timeouts and such.
|
||||
*/
|
||||
class Switch
|
||||
{
|
||||
public:
|
||||
explicit Switch(const RuntimeEnvironment *renv);
|
||||
|
||||
/**
|
||||
* Called when a packet is received from the real network
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param localSocket Local I/O socket as supplied by external code
|
||||
* @param fromAddr Internet IP address of origin
|
||||
* @param data Packet data
|
||||
* @param len Packet length
|
||||
*/
|
||||
void onRemotePacket(void *tPtr,int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len);
|
||||
|
||||
/**
|
||||
* Called when a packet comes from a local Ethernet tap
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param network Which network's TAP did this packet come from?
|
||||
* @param from Originating MAC address
|
||||
* @param to Destination MAC address
|
||||
* @param etherType Ethernet packet type
|
||||
* @param vlanId VLAN ID or 0 if none
|
||||
* @param data Ethernet payload
|
||||
* @param len Frame length
|
||||
*/
|
||||
void onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
|
||||
|
||||
/**
|
||||
* Send a packet to a ZeroTier address (destination in packet)
|
||||
*
|
||||
* The packet must be fully composed with source and destination but not
|
||||
* yet encrypted. If the destination peer is known the packet
|
||||
* is sent immediately. Otherwise it is queued and a WHOIS is dispatched.
|
||||
*
|
||||
* The packet may be compressed. Compression isn't done here.
|
||||
*
|
||||
* Needless to say, the packet's source must be this node. Otherwise it
|
||||
* won't be encrypted right. (This is not used for relaying.)
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param packet Packet to send (buffer may be modified)
|
||||
* @param encrypt Encrypt packet payload? (always true except for HELLO)
|
||||
*/
|
||||
void send(void *tPtr,Packet &packet,bool encrypt);
|
||||
|
||||
/**
|
||||
* Request WHOIS on a given address
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param now Current time
|
||||
* @param addr Address to look up
|
||||
*/
|
||||
void requestWhois(void *tPtr,int64_t now,const Address &addr);
|
||||
|
||||
/**
|
||||
* Run any processes that are waiting for this peer's identity
|
||||
*
|
||||
* Called when we learn of a peer's identity from HELLO, OK(WHOIS), etc.
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param peer New peer
|
||||
*/
|
||||
void doAnythingWaitingForPeer(void *tPtr,const SharedPtr<Peer> &peer);
|
||||
|
||||
/**
|
||||
* Perform retries and other periodic timer tasks
|
||||
*
|
||||
* This can return a very long delay if there are no pending timer
|
||||
* tasks. The caller should cap this comparatively vs. other values.
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param now Current time
|
||||
* @return Number of milliseconds until doTimerTasks() should be run again
|
||||
*/
|
||||
unsigned long doTimerTasks(void *tPtr,int64_t now);
|
||||
|
||||
private:
|
||||
bool _trySend(void *tPtr,Packet &packet,bool encrypt); // packet is modified if return is true
|
||||
|
||||
const RuntimeEnvironment *const RR;
|
||||
volatile int64_t _lastCheckedQueues;
|
||||
|
||||
// Time we last sent a WHOIS request for each address
|
||||
Hashtable< Address,int64_t > _lastSentWhoisRequest;
|
||||
Mutex _lastSentWhoisRequest_m;
|
||||
|
||||
// Packets waiting for WHOIS replies or other decode info or missing fragments
|
||||
struct RXQueueEntry
|
||||
{
|
||||
ZT_ALWAYS_INLINE RXQueueEntry() : timestamp(0) {}
|
||||
volatile int64_t timestamp; // 0 if entry is not in use
|
||||
volatile uint64_t packetId;
|
||||
IncomingPacket frag0; // head of packet
|
||||
Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any)
|
||||
unsigned int totalFragments; // 0 if only frag0 received, waiting for frags
|
||||
uint32_t haveFragments; // bit mask, LSB to MSB
|
||||
volatile bool complete; // if true, packet is complete
|
||||
Mutex lock;
|
||||
};
|
||||
RXQueueEntry _rxQueue[ZT_RX_QUEUE_SIZE];
|
||||
AtomicCounter<unsigned int> _rxQueuePtr;
|
||||
|
||||
// Returns matching or next available RX queue entry
|
||||
ZT_ALWAYS_INLINE RXQueueEntry *_findRXQueueEntry(uint64_t packetId)
|
||||
{
|
||||
const unsigned int current = static_cast<unsigned int>(_rxQueuePtr.load());
|
||||
for(unsigned int k=1;k<=ZT_RX_QUEUE_SIZE;++k) {
|
||||
RXQueueEntry *rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]);
|
||||
if ((rq->packetId == packetId)&&(rq->timestamp))
|
||||
return rq;
|
||||
}
|
||||
++_rxQueuePtr;
|
||||
return &(_rxQueue[static_cast<unsigned int>(current) % ZT_RX_QUEUE_SIZE]);
|
||||
}
|
||||
|
||||
// Returns current entry in rx queue ring buffer and increments ring pointer
|
||||
ZT_ALWAYS_INLINE RXQueueEntry *_nextRXQueueEntry()
|
||||
{
|
||||
return &(_rxQueue[static_cast<unsigned int>((++_rxQueuePtr) - 1) % ZT_RX_QUEUE_SIZE]);
|
||||
}
|
||||
|
||||
// ZeroTier-layer TX queue entry
|
||||
struct TXQueueEntry
|
||||
{
|
||||
ZT_ALWAYS_INLINE TXQueueEntry() {}
|
||||
ZT_ALWAYS_INLINE TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc) :
|
||||
dest(d),
|
||||
creationTime(ct),
|
||||
packet(p),
|
||||
encrypt(enc) {}
|
||||
|
||||
Address dest;
|
||||
uint64_t creationTime;
|
||||
Packet packet; // unencrypted/unMAC'd packet -- this is done at send time
|
||||
bool encrypt;
|
||||
};
|
||||
std::list< TXQueueEntry > _txQueue;
|
||||
Mutex _txQueue_m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Debug macros
|
||||
*/
|
||||
|
||||
#ifndef ZT_DEBUG_H
|
||||
#define ZT_DEBUG_H
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include <sys/syscall.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define ZT_MSG_INFO true
|
||||
#define ZT_COLOR true
|
||||
|
||||
// Debug output colors
|
||||
#if defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
#if defined(ZT_COLOR) && !defined(_WIN32) && !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(__APP_FRAMEWORK__)
|
||||
#define ZT_RED "\x1B[31m"
|
||||
#define ZT_GRN "\x1B[32m"
|
||||
#define ZT_YEL "\x1B[33m"
|
||||
#define ZT_BLU "\x1B[34m"
|
||||
#define ZT_MAG "\x1B[35m"
|
||||
#define ZT_CYN "\x1B[36m"
|
||||
#define ZT_WHT "\x1B[37m"
|
||||
#define ZT_RESET "\x1B[0m"
|
||||
#else
|
||||
#define ZT_RED
|
||||
#define ZT_GRN
|
||||
#define ZT_YEL
|
||||
#define ZT_BLU
|
||||
#define ZT_MAG
|
||||
#define ZT_CYN
|
||||
#define ZT_WHT
|
||||
#define ZT_RESET
|
||||
#endif
|
||||
|
||||
#define ZT_FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // short
|
||||
|
||||
#ifdef __linux__
|
||||
#define ZT_THREAD_ID (long)0 // syscall(SYS_gettid)
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#define ZT_THREAD_ID (long)0 // (long)gettid()
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
#define ZT_THREAD_ID (long)0 // (long)gettid()
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#define ZT_THREAD_ID (long)0 //
|
||||
#endif
|
||||
#if defined(__JNI_LIB__)
|
||||
#include <jni.h>
|
||||
#endif
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#define ZT_LOG_TAG "ZTSDK"
|
||||
#endif
|
||||
#if defined(ZT_DEBUG_TRACE)
|
||||
#if ZT_MSG_INFO == true
|
||||
#if defined(__ANDROID__)
|
||||
#define DEBUG_INFO(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \
|
||||
"INFO : %17s:%5d:%20s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
#define DEBUG_INFO(fmt, ...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" \
|
||||
ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, __VA_ARGS__)
|
||||
#endif
|
||||
#if defined(__linux__) or defined(__APPLE__) or defined(__FreeBSD__)
|
||||
#define DEBUG_INFO(fmt, args ...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" \
|
||||
ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_INFO(fmt, args...)
|
||||
#endif
|
||||
#else // blank
|
||||
#if defined(_WIN32)
|
||||
#define DEBUG_INFO(...)
|
||||
#else
|
||||
#define DEBUG_INFO(fmt, args...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // _H
|
|
@ -1,40 +0,0 @@
|
|||
CORE_OBJS=\
|
||||
node/AES.o \
|
||||
node/C25519.o \
|
||||
node/Credential.o \
|
||||
node/ECC384.o \
|
||||
node/Identity.o \
|
||||
node/IncomingPacket.o \
|
||||
node/InetAddress.o \
|
||||
node/Membership.o \
|
||||
node/Multicaster.o \
|
||||
node/Network.o \
|
||||
node/NetworkConfig.o \
|
||||
node/Node.o \
|
||||
node/OutboundMulticast.o \
|
||||
node/Packet.o \
|
||||
node/Path.o \
|
||||
node/Peer.o \
|
||||
node/Poly1305.o \
|
||||
node/Salsa20.o \
|
||||
node/SelfAwareness.o \
|
||||
node/SHA512.o \
|
||||
node/Switch.o \
|
||||
node/Trace.o \
|
||||
node/Utils.o
|
||||
|
||||
ONE_OBJS=\
|
||||
controller/EmbeddedNetworkController.o \
|
||||
controller/DBMirrorSet.o \
|
||||
controller/DB.o \
|
||||
controller/FileDB.o \
|
||||
controller/LFDB.o \
|
||||
controller/PostgreSQL.o \
|
||||
controller/RabbitMQ.o \
|
||||
osdep/EthernetTap.o \
|
||||
osdep/ManagedRoute.o \
|
||||
osdep/Http.o \
|
||||
osdep/OSUtils.o \
|
||||
service/SoftwareUpdater.o \
|
||||
service/OneService.o
|
||||
|
|
@ -14,6 +14,4 @@ target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11)
|
|||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/node
|
||||
${CMAKE_SOURCE_DIR}/osdep
|
||||
${CMAKE_SOURCE_DIR}/ext/json
|
||||
${CMAKE_SOURCE_DIR}/ext/cpp-httplib
|
||||
)
|
|
@ -32,7 +32,7 @@
|
|||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
#include "../ext/json/json.hpp"
|
||||
#include "./thirdparty/json/json.hpp"
|
||||
|
||||
namespace ZeroTier
|
||||
{
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "../osdep/Thread.hpp"
|
||||
#include "../osdep/BlockingQueue.hpp"
|
||||
|
||||
#include "../ext/json/json.hpp"
|
||||
#include "./thirdparty/json/json.hpp"
|
||||
|
||||
#include "DB.hpp"
|
||||
#include "DBMirrorSet.hpp"
|
||||
|
|
21
controller/thirdparty/json/LICENSE.MIT
vendored
Normal file
21
controller/thirdparty/json/LICENSE.MIT
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2013-2017 Niels Lohmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
1123
controller/thirdparty/json/README.md
vendored
Normal file
1123
controller/thirdparty/json/README.md
vendored
Normal file
File diff suppressed because it is too large
Load diff
18912
controller/thirdparty/json/json.hpp
vendored
Normal file
18912
controller/thirdparty/json/json.hpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,49 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
export PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
||||
shopt -s expand_aliases
|
||||
|
||||
if [ "$UID" -ne 0 ]; then
|
||||
echo '*** Auto-updater must be run as root.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
scriptPath="`dirname "$0"`/`basename "$0"`"
|
||||
if [ ! -s "$scriptPath" ]; then
|
||||
scriptPath="$0"
|
||||
if [ ! -s "$scriptPath" ]; then
|
||||
echo "*** Auto-updater cannot determine its own path; $scriptPath is not readable."
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
endMarkerIndex=`grep -a -b -E '^################' "$scriptPath" | head -c 16 | cut -d : -f 1`
|
||||
if [ "$endMarkerIndex" -le 100 ]; then
|
||||
echo 'Internal error: unable to find end of script / start of binary data marker.'
|
||||
exit 2
|
||||
fi
|
||||
blobStart=`expr $endMarkerIndex + 17`
|
||||
if [ "$blobStart" -le "$endMarkerIndex" ]; then
|
||||
echo 'Internal error: unable to find end of script / start of binary data marker.'
|
||||
exit 2
|
||||
fi
|
||||
|
||||
rm -f /tmp/ZeroTierOne-update.pkg
|
||||
tail -c +$blobStart "$scriptPath" >/tmp/ZeroTierOne-update.pkg
|
||||
chmod 0600 /tmp/ZeroTierOne-update.pkg
|
||||
|
||||
if [ -s /tmp/ZeroTierOne-update.pkg ]; then
|
||||
rm -f '/Library/Application Support/ZeroTier/One/latest-update.exe' '/Library/Application Support/ZeroTier/One/latest-update.json' /tmp/ZeroTierOne-update.log
|
||||
installer -verbose -pkg /tmp/ZeroTierOne-update.pkg -target / >/tmp/ZeroTierOne-update.log 2>&1
|
||||
rm -f /tmp/ZeroTierOne-update.pkg
|
||||
exit 0
|
||||
else
|
||||
echo '*** Error self-unpacking update!'
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# Do not remove the last line or add a carriage return to it! The installer
|
||||
# looks for an unterminated line beginning with 16 #'s in itself to find
|
||||
# the binary blob data, which is appended after it.
|
||||
|
||||
################
|
|
@ -1,47 +0,0 @@
|
|||
---
|
||||
# BasedOnStyle: Google
|
||||
AccessModifierOffset: -1
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BinPackParameters: true
|
||||
ColumnLimit: 80
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
DerivePointerBinding: true
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
IndentCaseLabels: true
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 60
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerBindsToType: true
|
||||
SpacesBeforeTrailingComments: 2
|
||||
Cpp11BracedListStyle: true
|
||||
Standard: Auto
|
||||
IndentWidth: 2
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
BreakBeforeBraces: Attach
|
||||
IndentFunctionDeclarationAfterType: true
|
||||
SpacesInParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpaceAfterControlStatementKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
ContinuationIndentWidth: 4
|
||||
...
|
||||
|
18
ext/librabbitmq/.gitattributes
vendored
18
ext/librabbitmq/.gitattributes
vendored
|
@ -1,18 +0,0 @@
|
|||
# Default for those who don't have core.autocrlf set
|
||||
* text=auto
|
||||
|
||||
# Things that should be treated like text (lines converted on checkout):
|
||||
*.c text
|
||||
*.h text
|
||||
*.py text
|
||||
*.cmake text
|
||||
*.md text
|
||||
# This is for the output of table_test
|
||||
*.expected text
|
||||
*.xml
|
||||
|
||||
# Exceptions to the rule:
|
||||
*.ac text eol=lf
|
||||
*.am text eol=lf
|
||||
*.m4 text eol=lf
|
||||
|
73
ext/librabbitmq/.gitignore
vendored
73
ext/librabbitmq/.gitignore
vendored
|
@ -1,73 +0,0 @@
|
|||
*.la
|
||||
*.lo
|
||||
*.o
|
||||
.deps
|
||||
.dirstamp
|
||||
.libs
|
||||
/aclocal.m4
|
||||
/autom4te.cache
|
||||
/bin*
|
||||
/build
|
||||
/compile
|
||||
/config.guess
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.h.in~
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/cscope.*
|
||||
/depcomp
|
||||
/install-sh
|
||||
/libtool
|
||||
/ltmain.sh
|
||||
/missing
|
||||
/stamp-h1
|
||||
/test-suite.log
|
||||
INSTALL
|
||||
Makefile
|
||||
Makefile.in
|
||||
examples/amqp_bind
|
||||
examples/amqp_connect_timeout
|
||||
examples/amqp_consumer
|
||||
examples/amqp_exchange_declare
|
||||
examples/amqp_listen
|
||||
examples/amqp_listenq
|
||||
examples/amqp_producer
|
||||
examples/amqp_rpc_sendstring_client
|
||||
examples/amqp_sendstring
|
||||
examples/amqp_unbind
|
||||
examples/amqps_bind
|
||||
examples/amqps_connect_timeout
|
||||
examples/amqps_consumer
|
||||
examples/amqps_exchange_declare
|
||||
examples/amqps_listen
|
||||
examples/amqps_listenq
|
||||
examples/amqps_producer
|
||||
examples/amqps_sendstring
|
||||
examples/amqps_unbind
|
||||
librabbitmq.pc
|
||||
test-driver
|
||||
tests/*.log
|
||||
tests/*.trs
|
||||
tests/test_hostcheck
|
||||
tests/test_parse_url
|
||||
tests/test_status_enum
|
||||
tests/test_tables
|
||||
tools/amqp-consume
|
||||
tools/amqp-declare-queue
|
||||
tools/amqp-delete-queue
|
||||
tools/amqp-get
|
||||
tools/amqp-publish
|
||||
tools/doc/*.1
|
||||
tools/doc/*.7
|
||||
tools/doc/man-date.ent
|
||||
.ycm_extra_conf.py?
|
||||
.DS_Store
|
||||
|
||||
# Ignore editor swap files
|
||||
*~
|
||||
*.sw?
|
||||
.#*
|
||||
\#*#
|
6
ext/librabbitmq/.gitmodules
vendored
6
ext/librabbitmq/.gitmodules
vendored
|
@ -1,6 +0,0 @@
|
|||
[submodule "codegen"]
|
||||
path = codegen
|
||||
url = https://github.com/rabbitmq/rabbitmq-codegen.git
|
||||
[submodule "travis/run-clang-format"]
|
||||
path = travis/run-clang-format
|
||||
url = https://github.com/Sarcasm/run-clang-format.git
|
|
@ -1,92 +0,0 @@
|
|||
# Travis-CI Build for rabbitmq-c
|
||||
# see travis-ci.org for details
|
||||
|
||||
language: c
|
||||
|
||||
dist: trusty
|
||||
# Currently libpopt-dev is not on the list of whitelisted apt-packages.
|
||||
sudo: true
|
||||
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
- secure: "gDwqo3jHj+HHGzFKnxL/nwZhbVeh2pItw0TbeaHcLtWubUZaf85ViEQRaXPyfnbG7l0OEQq+PjyhKAfvViVq2NP0lGeeu4VM5uMZJhsCLN594BJr39Y4XzOapg0O8mEMhQ0DU2u1Zo4LMgEcRz67aosVQOj6QV30tOzp9fnxn9U="
|
||||
|
||||
services:
|
||||
- rabbitmq
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# Note that the first compiler in the matrix must be gcc, so that the
|
||||
# coverity_scan branch hack below works correctly.
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: CONFIG=cmake
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: CONFIG=format
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: CONFIG=coverage
|
||||
- compiler: clang
|
||||
os: linux
|
||||
env: CONFIG=cmake
|
||||
- compiler: clang
|
||||
os: linux
|
||||
env: CONFIG=asan
|
||||
- compiler: clang
|
||||
os: linux
|
||||
env: CONFIG=tsan
|
||||
- compiler: clang
|
||||
os: linux
|
||||
env: CONFIG=scan-build
|
||||
- compiler: clang
|
||||
os: osx
|
||||
env: CONFIG=cmake
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: NAME="openssl-1.1.0" CONFIG=cmake
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ondrej/nginx-mainline'
|
||||
packages:
|
||||
- libssl1.1
|
||||
- openssl
|
||||
- libssl-dev
|
||||
|
||||
allow_failures:
|
||||
- compiler: clang
|
||||
os: linux
|
||||
env: CONFIG=tsan
|
||||
|
||||
before_install:
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main"
|
||||
sudo apt-get -q update;
|
||||
sudo apt-get install -y clang-3.9 clang-format-3.9 libpopt-dev;
|
||||
fi
|
||||
# ugly hack; if running a coverity scan abort all except the 1st build
|
||||
# see note re gcc compiler above needing to be 1st
|
||||
# also note that branch_pattern & the TRAVIS_BRANCH check must match
|
||||
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
|
||||
# build process
|
||||
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
|
||||
|
||||
|
||||
script:
|
||||
# Don't bother building if this is being done in the coverity_scan branch.
|
||||
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./travis.sh $CONFIG ; fi
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "alanxz/rabbitmq-c"
|
||||
description: "C AMQP client for RabbitMQ"
|
||||
notification_email: alan.antonuk@gmail.com
|
||||
build_command_prepend: mkdir build && pushd build && cmake .. && popd
|
||||
build_command: cmake --build ./build
|
||||
branch_pattern: coverity_scan
|
|
@ -1,157 +0,0 @@
|
|||
# This file is NOT licensed under the GPLv3, which is the license for the rest
|
||||
# of YouCompleteMe.
|
||||
#
|
||||
# Here's the license text for this file:
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
#
|
||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
# distribute this software, either in source code form or as a compiled
|
||||
# binary, for any purpose, commercial or non-commercial, and by any
|
||||
# means.
|
||||
#
|
||||
# In jurisdictions that recognize copyright laws, the author or authors
|
||||
# of this software dedicate any and all copyright interest in the
|
||||
# software to the public domain. We make this dedication for the benefit
|
||||
# of the public at large and to the detriment of our heirs and
|
||||
# successors. We intend this dedication to be an overt act of
|
||||
# relinquishment in perpetuity of all present and future rights to this
|
||||
# software under copyright law.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
import os
|
||||
import ycm_core
|
||||
|
||||
# These are the compilation flags that will be used in case there's no
|
||||
# compilation database set (by default, one is not set).
|
||||
# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
|
||||
flags = [
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
# THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't know which
|
||||
# language to use when compiling headers. So it will guess. Badly. So C++
|
||||
# headers will be compiled as C headers. You don't want that so ALWAYS specify
|
||||
# a "-std=<something>".
|
||||
# For a C project, you would set this to something like 'c99' instead of
|
||||
# 'c++11'.
|
||||
'-std=gnu90',
|
||||
# ...and the same thing goes for the magic -x option which specifies the
|
||||
# language that the files to be compiled are written in. This is mostly
|
||||
# relevant for c++ headers.
|
||||
# For a C project, you would set this to 'c' instead of 'c++'.
|
||||
'-x',
|
||||
'c',
|
||||
'-I', './librabbitmq',
|
||||
'-I', './librabbitmq/unix',
|
||||
'-D', 'HAVE_POLL',
|
||||
]
|
||||
|
||||
|
||||
# Set this to the absolute path to the folder (NOT the file!) containing the
|
||||
# compile_commands.json file to use that instead of 'flags'. See here for
|
||||
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
|
||||
#
|
||||
# You can get CMake to generate this file for you by adding:
|
||||
# set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
|
||||
# to your CMakeLists.txt file.
|
||||
#
|
||||
# Most projects will NOT need to set this to anything; you can just change the
|
||||
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
|
||||
compilation_database_folder = ''
|
||||
|
||||
if os.path.exists( compilation_database_folder ):
|
||||
database = ycm_core.CompilationDatabase( compilation_database_folder )
|
||||
else:
|
||||
database = None
|
||||
|
||||
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
|
||||
|
||||
def DirectoryOfThisScript():
|
||||
return os.path.dirname( os.path.abspath( __file__ ) )
|
||||
|
||||
|
||||
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
|
||||
if not working_directory:
|
||||
return list( flags )
|
||||
new_flags = []
|
||||
make_next_absolute = False
|
||||
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
|
||||
for flag in flags:
|
||||
new_flag = flag
|
||||
|
||||
if make_next_absolute:
|
||||
make_next_absolute = False
|
||||
if not flag.startswith( '/' ):
|
||||
new_flag = os.path.join( working_directory, flag )
|
||||
|
||||
for path_flag in path_flags:
|
||||
if flag == path_flag:
|
||||
make_next_absolute = True
|
||||
break
|
||||
|
||||
if flag.startswith( path_flag ):
|
||||
path = flag[ len( path_flag ): ]
|
||||
new_flag = path_flag + os.path.join( working_directory, path )
|
||||
break
|
||||
|
||||
if new_flag:
|
||||
new_flags.append( new_flag )
|
||||
return new_flags
|
||||
|
||||
|
||||
def IsHeaderFile( filename ):
|
||||
extension = os.path.splitext( filename )[ 1 ]
|
||||
return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
|
||||
|
||||
|
||||
def GetCompilationInfoForFile( filename ):
|
||||
# The compilation_commands.json file generated by CMake does not have entries
|
||||
# for header files. So we do our best by asking the db for flags for a
|
||||
# corresponding source file, if any. If one exists, the flags for that file
|
||||
# should be good enough.
|
||||
if IsHeaderFile( filename ):
|
||||
basename = os.path.splitext( filename )[ 0 ]
|
||||
for extension in SOURCE_EXTENSIONS:
|
||||
replacement_file = basename + extension
|
||||
if os.path.exists( replacement_file ):
|
||||
compilation_info = database.GetCompilationInfoForFile(
|
||||
replacement_file )
|
||||
if compilation_info.compiler_flags_:
|
||||
return compilation_info
|
||||
return None
|
||||
return database.GetCompilationInfoForFile( filename )
|
||||
|
||||
|
||||
def FlagsForFile( filename, **kwargs ):
|
||||
if database:
|
||||
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
|
||||
# python list, but a "list-like" StringVec object
|
||||
compilation_info = GetCompilationInfoForFile( filename )
|
||||
if not compilation_info:
|
||||
relative_to = DirectoryOfThisScript()
|
||||
return {
|
||||
'flags': MakeRelativePathsInFlagsAbsolute( flags, relative_to ),
|
||||
'do_cache': True
|
||||
}
|
||||
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute(
|
||||
compilation_info.compiler_flags_,
|
||||
compilation_info.compiler_working_dir_ )
|
||||
|
||||
else:
|
||||
relative_to = DirectoryOfThisScript()
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
|
||||
|
||||
return {
|
||||
'flags': final_flags,
|
||||
'do_cache': True
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
Tony Garnock-Jones <tonygarnockjones@gmail.com>
|
||||
The RabbitMQ team <info@rabbitmq.com>
|
|
@ -1,343 +0,0 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(rabbitmq-c "C")
|
||||
|
||||
# Enable MACOSX_RPATH by default. See: cmake --help-policy CMP0042
|
||||
if (POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif()
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
# Follow all steps below in order to calculate new ABI version when updating the library
|
||||
# NOTE: THIS IS UNRELATED to the actual project version
|
||||
#
|
||||
# 1. If the library source code has changed at all since the last update, then increment revision
|
||||
# 2. If any interfaces have been added, removed, or changed since the last update, increment current and set revision to 0.
|
||||
# 3. If any interfaces have been added since the last public release, then increment age.
|
||||
# 4. If any interfaces have been removed since the last public release, then set age to 0.
|
||||
|
||||
set(RMQ_SOVERSION_CURRENT 7)
|
||||
set(RMQ_SOVERSION_REVISION 0)
|
||||
set(RMQ_SOVERSION_AGE 3)
|
||||
|
||||
math(EXPR RMQ_SOVERSION_MAJOR "${RMQ_SOVERSION_CURRENT} - ${RMQ_SOVERSION_AGE}")
|
||||
math(EXPR RMQ_SOVERSION_MINOR "${RMQ_SOVERSION_AGE}")
|
||||
math(EXPR RMQ_SOVERSION_PATCH "${RMQ_SOVERSION_REVISION}")
|
||||
|
||||
set(RMQ_VERSION ${RMQ_SOVERSION_MAJOR}.${RMQ_SOVERSION_MINOR}.${RMQ_SOVERSION_PATCH})
|
||||
set(RMQ_SOVERSION ${RMQ_SOVERSION_MAJOR})
|
||||
|
||||
file(STRINGS librabbitmq/amqp.h _API_VERSION_MAJOR REGEX "^#define AMQP_VERSION_MAJOR [0-9]+$")
|
||||
file(STRINGS librabbitmq/amqp.h _API_VERSION_MINOR REGEX "^#define AMQP_VERSION_MINOR [0-9]+$")
|
||||
file(STRINGS librabbitmq/amqp.h _API_VERSION_PATCH REGEX "^#define AMQP_VERSION_PATCH [0-9]+$")
|
||||
|
||||
string(REGEX MATCH "[0-9]+" _API_VERSION_MAJOR ${_API_VERSION_MAJOR})
|
||||
string(REGEX MATCH "[0-9]+" _API_VERSION_MINOR ${_API_VERSION_MINOR})
|
||||
string(REGEX MATCH "[0-9]+" _API_VERSION_PATCH ${_API_VERSION_PATCH})
|
||||
|
||||
# VERSION to match what is in autotools
|
||||
set(VERSION ${_API_VERSION_MAJOR}.${_API_VERSION_MINOR}.${_API_VERSION_PATCH})
|
||||
|
||||
if (CMAKE_GENERATOR MATCHES ".*(Make|Ninja).*"
|
||||
AND NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
|
||||
message(STATUS "CMAKE_BUILD_TYPE not specified. Creating ${CMAKE_BUILD_TYPE} build")
|
||||
endif()
|
||||
|
||||
include(TestCInline)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckLibraryExists)
|
||||
include(CMakePushCheckState)
|
||||
include(GNUInstallDirs)
|
||||
include(CheckCCompilerFlag)
|
||||
|
||||
# Detect if we need to link against a socket library:
|
||||
cmake_push_check_state()
|
||||
if (WIN32)
|
||||
# Always use WinSock2 on Windows
|
||||
set(SOCKET_LIBRARIES ws2_32)
|
||||
else ()
|
||||
# Is it in the default link?
|
||||
check_symbol_exists(getaddrinfo "sys/types.h;sys/socket.h;netdb.h" HAVE_GETADDRINFO)
|
||||
if (NOT (HAVE_GETADDRINFO EQUAL 1))
|
||||
SET(CMAKE_REQUIRED_LIBRARIES "socket")
|
||||
check_symbol_exists(getaddrinfo "sys/types.h;sys/socket.h;netdb.h" HAVE_GETADDRINFO2)
|
||||
if (HAVE_GETADDRINFO2 EQUAL 1)
|
||||
set(SOCKET_LIBRARIES socket)
|
||||
else ()
|
||||
SET(CMAKE_REQUIRED_LIBRARIES "socket;nsl")
|
||||
check_symbol_exists(getaddrinfo "sys/types.h;sys/socket.h;netdb.h" HAVE_GETADDRINFO3)
|
||||
if (HAVE_GETADDRINFO3 EQUAL 1)
|
||||
set(SOCKET_LIBRARIES socket nsl)
|
||||
else ()
|
||||
message(FATAL_ERROR "Cannot find name resolution library (containing symbol getaddrinfo)")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${SOCKET_LIBRARIES})
|
||||
check_symbol_exists(socket "sys/types.h;sys/socket.h" HAVE_SOCKET)
|
||||
if (NOT HAVE_SOCKET EQUAL 1)
|
||||
set(CMAKE_REQUIRED_LIBRARIES socket ${SOCKET_LIBRARIES})
|
||||
check_symbol_exists(socket "sys/types.h;sys/socket.h" HAVE_SOCKET2)
|
||||
if (HAVE_SOCKET2 EQUAL 1)
|
||||
set(SOCKET_LIBRARIES socket ${SOCKET_LIBRARIES})
|
||||
else ()
|
||||
set(CMAKE_REQUIRED_LIBRARIES socket nsl ${SOCKET_LIBRARIES})
|
||||
check_symbol_exists(socket "sys/types.h;sys/socket.h" HAVE_SOCKET3)
|
||||
if (HAVE_SOCKET3 EQUAL 1)
|
||||
set(SOCKET_LIBRARIES socket nsl ${SOCKET_LIBRARIES})
|
||||
else ()
|
||||
message(FATAL_ERROR "Cannot find socket library (containing symbol socket)")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
cmake_pop_check_state()
|
||||
|
||||
cmake_push_check_state()
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${SOCKET_LIBRARIES})
|
||||
check_symbol_exists(poll poll.h HAVE_POLL)
|
||||
if (NOT HAVE_POLL)
|
||||
if (WIN32)
|
||||
set(HAVE_SELECT 1)
|
||||
else()
|
||||
check_symbol_exists(select sys/select.h HAVE_SELECT)
|
||||
endif()
|
||||
if (NOT HAVE_SELECT)
|
||||
message(FATAL_ERROR "rabbitmq-c requires poll() or select() to be available")
|
||||
endif()
|
||||
endif()
|
||||
cmake_pop_check_state()
|
||||
|
||||
check_library_exists(rt clock_gettime "time.h" CLOCK_GETTIME_NEEDS_LIBRT)
|
||||
check_library_exists(rt posix_spawnp "spawn.h" POSIX_SPAWNP_NEEDS_LIBRT)
|
||||
if (CLOCK_GETTIME_NEEDS_LIBRT OR POSIX_SPAWNP_NEEDS_LIBRT)
|
||||
set(LIBRT rt)
|
||||
endif()
|
||||
|
||||
option(ENABLE_SSL_SUPPORT "Enable SSL support" ON)
|
||||
|
||||
if (ENABLE_SSL_SUPPORT)
|
||||
find_package(OpenSSL 0.9.8 REQUIRED)
|
||||
|
||||
cmake_push_check_state()
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set(CMAKE_C_FLAGS "/W4 /nologo ${CMAKE_C_FLAGS}")
|
||||
elseif (CMAKE_C_COMPILER_ID MATCHES ".*Clang")
|
||||
set(CMAKE_C_FLAGS "-Wall -Wextra -Wstrict-prototypes -Wno-unused-function -fno-common -fvisibility=hidden ${CMAKE_C_FLAGS}")
|
||||
elseif (CMAKE_COMPILER_IS_GNUCC)
|
||||
set(RMQ_C_FLAGS "-Wall -Wextra -Wstrict-prototypes -Wno-unused-function -fno-common")
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||
if (GCC_VERSION VERSION_GREATER 4.0 OR GCC_VERSION VERSION_EQUAL 4.0)
|
||||
set(RMQ_C_FLAGS "${RMQ_C_FLAGS} -fvisibility=hidden")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${RMQ_C_FLAGS} ${CMAKE_C_FLAGS}")
|
||||
endif ()
|
||||
|
||||
CHECK_C_COMPILER_FLAG("-std=gnu90" HAVE_GNU90)
|
||||
if (HAVE_GNU90)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu90")
|
||||
else()
|
||||
CHECK_C_COMPILER_FLAG("-std=c90" HAVE_C90)
|
||||
if (HAVE_C90)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c90")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(REGENERATE_AMQP_FRAMING "Regenerate amqp_framing.h/amqp_framing.c sources (for developer use)" OFF)
|
||||
mark_as_advanced(REGENERATE_AMQP_FRAMING)
|
||||
|
||||
if (REGENERATE_AMQP_FRAMING)
|
||||
find_package(PythonInterp)
|
||||
if (NOT PYTHONINTERP_FOUND)
|
||||
message(FATAL_ERROR "REGENERATE_AMQP_FRAMING requires Python to be available")
|
||||
endif ()
|
||||
|
||||
#Determine Python Version:
|
||||
if(PYTHON_EXECUTABLE)
|
||||
execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c
|
||||
"import sys; sys.stdout.write(';'.join([str(x) for x in sys.version_info[:3]]))"
|
||||
OUTPUT_VARIABLE _VERSION
|
||||
RESULT_VARIABLE _PYTHON_VERSION_RESULT
|
||||
ERROR_QUIET)
|
||||
if(NOT _PYTHON_VERSION_RESULT)
|
||||
string(REPLACE ";" "." PYTHON_VERSION_STRING "${_VERSION}")
|
||||
list(GET _VERSION 0 PYTHON_VERSION_MAJOR)
|
||||
list(GET _VERSION 1 PYTHON_VERSION_MINOR)
|
||||
list(GET _VERSION 2 PYTHON_VERSION_PATCH)
|
||||
if(PYTHON_VERSION_PATCH EQUAL 0)
|
||||
# it's called "Python 2.7", not "2.7.0"
|
||||
string(REGEX REPLACE "\\.0$" "" PYTHON_VERSION_STRING "${PYTHON_VERSION_STRING}")
|
||||
endif()
|
||||
else()
|
||||
# sys.version predates sys.version_info, so use that
|
||||
execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.version)"
|
||||
OUTPUT_VARIABLE _VERSION
|
||||
RESULT_VARIABLE _PYTHON_VERSION_RESULT
|
||||
ERROR_QUIET)
|
||||
if(NOT _PYTHON_VERSION_RESULT)
|
||||
string(REGEX REPLACE " .*" "" PYTHON_VERSION_STRING "${_VERSION}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.[0-9]+.*" "\\1" PYTHON_VERSION_MAJOR "${PYTHON_VERSION_STRING}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.([0-9])+.*" "\\1" PYTHON_VERSION_MINOR "${PYTHON_VERSION_STRING}")
|
||||
if(PYTHON_VERSION_STRING MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+.*")
|
||||
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" PYTHON_VERSION_PATCH "${PYTHON_VERSION_STRING}")
|
||||
else()
|
||||
set(PYTHON_VERSION_PATCH "0")
|
||||
endif()
|
||||
else()
|
||||
# sys.version was first documented for Python 1.5, so assume
|
||||
# this is older.
|
||||
set(PYTHON_VERSION_STRING "1.4")
|
||||
set(PYTHON_VERSION_MAJOR "1")
|
||||
set(PYTHON_VERSION_MAJOR "4")
|
||||
set(PYTHON_VERSION_MAJOR "0")
|
||||
endif()
|
||||
endif()
|
||||
unset(_PYTHON_VERSION_RESULT)
|
||||
unset(_VERSION)
|
||||
endif(PYTHON_EXECUTABLE)
|
||||
|
||||
# If we're running v3.x look for a 2to3 utility
|
||||
if (PYTHON_VERSION_MAJOR GREATER 2)
|
||||
get_filename_component(PYTHON_EXE_DIR ${PYTHON_EXECUTABLE} PATH)
|
||||
find_program(PYTHON_2TO3_EXECUTABLE
|
||||
NAMES 2to3
|
||||
HINTS ${PYTHON_EXE_DIR}
|
||||
)
|
||||
|
||||
if ("PYTHON_2TO3_EXECUTABLE-NOTFOUND" STREQUAL PYTHON_2TO3_EXECUTABLE)
|
||||
message(FATAL_ERROR "Unable to find 2to3 python utility, specify python 2.7 or specify 2to3 utility")
|
||||
endif ()
|
||||
endif (PYTHON_VERSION_MAJOR GREATER 2)
|
||||
|
||||
|
||||
#check for json or simplejson
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import json"
|
||||
RESULT_VARIABLE CHECK_PYTHON_JSON_FAILED
|
||||
)
|
||||
|
||||
if (CHECK_PYTHON_JSON_FAILED)
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import simplejson"
|
||||
RESULT_VARIABLE CHECK_PYTHON_SIMPLEJSON_FAILED
|
||||
)
|
||||
|
||||
if (CHECK_PYTHON_SIMPLEJSON_FAILED)
|
||||
message(FATAL_ERROR "REGENERATE_AMQP_FRAMING requires a python with json or simplejson modules")
|
||||
endif (CHECK_PYTHON_SIMPLEJSON_FAILED)
|
||||
endif (CHECK_PYTHON_JSON_FAILED)
|
||||
|
||||
|
||||
find_path(AMQP_CODEGEN_DIR
|
||||
amqp_codegen.py
|
||||
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/codegen
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rabbitmq-codegen
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../rabbitmq-codegen
|
||||
DOC "Path to directory containing amqp_codegen.py (rabbitmq-codegen)"
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
if (AMQP_CODEGEN_DIR STREQUAL "AMQP_CODEGEN_DIR-NOTFOUND")
|
||||
message(SEND_ERROR "REGENERATE_AMQP_FRAMING requires the amqp_codegen.py script. If this is a git clone you can:\n\ngit submodule init\ngit submodule update\n\n Or set AMQP_CODEGEN_DIR to directory containing amqp_codegen.py")
|
||||
else ()
|
||||
message(STATUS "Found amqp_codegen.py in ${AMQP_CODEGEN_DIR}")
|
||||
endif()
|
||||
endif (REGENERATE_AMQP_FRAMING)
|
||||
|
||||
find_package(POPT)
|
||||
find_package(XmlTo)
|
||||
find_package(Doxygen)
|
||||
|
||||
if (POPT_FOUND AND XmlTo_FOUND)
|
||||
set(DO_DOCS ON)
|
||||
endif()
|
||||
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build rabbitmq-c as a shared library" ON)
|
||||
option(BUILD_STATIC_LIBS "Build rabbitmq-c as a static library" ON)
|
||||
|
||||
option(BUILD_EXAMPLES "Build Examples" ON)
|
||||
option(BUILD_TOOLS "Build Tools (requires POPT Library)" ${POPT_FOUND})
|
||||
option(BUILD_TOOLS_DOCS "Build man pages for Tools (requires xmlto)" ${DO_DOCS})
|
||||
option(BUILD_TESTS "Build tests (run tests with make test)" ON)
|
||||
option(BUILD_API_DOCS "Build Doxygen API docs" ${DOXYGEN_FOUND})
|
||||
|
||||
if (NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS)
|
||||
message(FATAL_ERROR "One or both of BUILD_SHARED_LIBS or BUILD_STATIC_LIBS must be set to ON to build")
|
||||
endif()
|
||||
|
||||
add_subdirectory(librabbitmq)
|
||||
|
||||
if (BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif ()
|
||||
|
||||
if (BUILD_TOOLS)
|
||||
if (POPT_FOUND)
|
||||
add_subdirectory(tools)
|
||||
else ()
|
||||
message(WARNING "POpt library was not found. Tools will not be built")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (BUILD_TESTS)
|
||||
if (NOT BUILD_STATIC_LIBS)
|
||||
message(FATAL_ERROR
|
||||
"Tests can only be built against static libraries "
|
||||
"(set BUILD_STATIC_LIBS=ON)")
|
||||
endif ()
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif (BUILD_TESTS)
|
||||
|
||||
if (BUILD_API_DOCS)
|
||||
if (NOT DOXYGEN_FOUND)
|
||||
message(FATAL_ERROR "Doxygen is required to build the API documentation")
|
||||
endif ()
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/docs/Doxyfile @ONLY)
|
||||
|
||||
add_custom_target(docs
|
||||
COMMAND ${DOXYGEN_EXECUTABLE}
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs
|
||||
DEPENDS rabbitmq
|
||||
COMMENT "Generating API documentation"
|
||||
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in
|
||||
)
|
||||
endif ()
|
||||
|
||||
set(libs_private ${SOCKET_LIBRARIES} ${LIBRT})
|
||||
if (ENABLE_SSL_SUPPORT)
|
||||
set(requires_private "openssl")
|
||||
set(libs_private ${libs_private} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
set(prefix ${CMAKE_INSTALL_PREFIX})
|
||||
set(exec_prefix "\${prefix}")
|
||||
set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
|
||||
set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
configure_file(cmake/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/librabbitmq/config.h)
|
||||
configure_file(librabbitmq.pc.in ${CMAKE_CURRENT_BINARY_DIR}/librabbitmq.pc @ONLY)
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/librabbitmq.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
)
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
message(STATUS "Building rabbitmq as a shared library - yes")
|
||||
else ()
|
||||
message(STATUS "Building rabbitmq as a shared library - no")
|
||||
endif ()
|
||||
|
||||
if (BUILD_STATIC_LIBS)
|
||||
message(STATUS "Building rabbitmq as a static library - yes")
|
||||
else ()
|
||||
message(STATUS "Building rabbitmq as a static library - no")
|
||||
endif ()
|
|
@ -1,26 +0,0 @@
|
|||
Contributing to rabbitmq-c
|
||||
==========================
|
||||
|
||||
Thanks for contributing to rabbitmq-c. I firmly believe that participation helps
|
||||
make open source software great. With that there are a few things that can be
|
||||
done to make our interaction a bit smoother.
|
||||
|
||||
Please use the following guidelines when creating an issue or submitting a
|
||||
pull request
|
||||
|
||||
Creating an issue
|
||||
-----------------
|
||||
When submitting an issue its helpful to know the following
|
||||
- What version of rabbitmq-c are you using?
|
||||
- What operating system and version are you running on?
|
||||
- What compiler and version are you running?
|
||||
-
|
||||
- If its a build system issue: which build system are you using (
|
||||
|
||||
|
||||
Submitting a pull-request
|
||||
-------------------------
|
||||
I love to get code contributions, a few things that can help out:
|
||||
- Make sure your commits are rebased on the current master branch
|
||||
- Please collapse your commits down to a couple logical commits
|
||||
|
|
@ -1,221 +0,0 @@
|
|||
# Change Log
|
||||
## v0.9.0 - 2018-05-08
|
||||
### Added:
|
||||
- amqp-publish: added support for specifying headers via the -H flag
|
||||
- Add support for specifying timeout for amqp_login calls via
|
||||
amqp_set_handshake_timeout
|
||||
- Add support for specifying timeouts in RPC-style AMQP methods via
|
||||
amqp_set_rpc_timeout
|
||||
- Add define for `AMQP_DEFAULT_VHOST`
|
||||
- Support for SSL SNI
|
||||
- Support for OpenSSL v1.1.0
|
||||
|
||||
### Changed:
|
||||
- rabbitmq-c now requires Windows Vista or better
|
||||
- rabbitmq-c enables TCP keep-alive by default on platforms that support it
|
||||
- dropped support for compiling rabbitmq-c without threading support
|
||||
- OpenSSL is no longer un-intialized automatically by default. OpenSSL can be
|
||||
explicitly initialized by calling amqp_initialize_ssl_library and
|
||||
uninitialized by calling amqp_uninitialize_ssl_library.
|
||||
|
||||
### Fixed:
|
||||
- Correct bugs in processing of --url flag in tools (#364).
|
||||
- Improve documentation on AMQP_SASL_METHOD_EXTERNAL (#349)
|
||||
- Improve support for compiling under mingw-w64
|
||||
- Better support for handing SIGPIPE on Linux over SSL (#401)
|
||||
- Improve publish performance on Linux by not specifying MSG_MORE on last part
|
||||
of message.
|
||||
- Fix connection logic where multiple hostnames won't be tried if connection to
|
||||
doesn't fail immediately (#430)
|
||||
|
||||
### Removed:
|
||||
- autotools build system has been removed
|
||||
- many duplicate amqps_* examples, they did not add a lot of value
|
||||
|
||||
|
||||
## v0.8.0 - 2016-04-09
|
||||
### Added:
|
||||
- SSL: peer certificate and hostname validation can now be controlled separately
|
||||
using `amqp_ssl_socket_set_verify_peer` and
|
||||
`amqp_ssl_socket_set_verify_hostname`.
|
||||
- SSL: the desire SSL version range can now be specified using the
|
||||
`amqp_ssl_socket_set_ssl_versions` function.
|
||||
- Add flags to SSL examples on controlling hostname verification.
|
||||
|
||||
### Changed:
|
||||
- SSL: SSLv2, and SSLv3 have been disabled by default.
|
||||
- SSL: OpenSSL hostname validation has been improved.
|
||||
- Win32 debug information is built with /Z7 on MSVC to embed debug info instead
|
||||
of using a .pdb
|
||||
|
||||
### Fixed:
|
||||
- Connection failure results in hang on Win32 (#297, #346)
|
||||
- Rabbitmq-c may block when attempting to close an SSL socket (#313)
|
||||
- amqp_parse_url does not correctly initialize default parameters (#319)
|
||||
- x509 objects are leaked in verify_hostname (#323)
|
||||
- TCP_NOPUSH doesn't work under cygwin (#335)
|
||||
|
||||
### Deprecated
|
||||
- SSL: `amqp_ssl_socket_set_verify` is being replaced by
|
||||
`amqp_ssl_socket_set_verify_peer` and `amqp_ssl_socket_set_verify_hostname`.
|
||||
|
||||
### Removed:
|
||||
- OpenVMS build system and related files.
|
||||
- Unmaintained PolarSSL, CyaSSL, and gnuTLS SSL backends
|
||||
|
||||
## Changes since v0.7.0 (a.k.a., v0.7.1)
|
||||
- `41fa9df` Autoconf: add missing files in build system
|
||||
- `ef73c06` Win32: Use WSAEWOULDBLOCK instead of EWOULDBLOCK on Win32
|
||||
- `ceca348` CI: use travis-ci container based builds
|
||||
- `393e2df` Lib: if channel_max is 0 use server's channel_max
|
||||
- `ff47574` Lib: fix build on OpenBSD
|
||||
- `8429496...0ac6430` CI: enable CI on Mac OS X in travis-ci
|
||||
|
||||
## Changes since v0.6.0 (a.k.a., v0.7.0)
|
||||
- `3379812` Tools: Add support for heartbeats
|
||||
- `d7029db` CI: Add continuous integration on Win32 using Appveyor
|
||||
- `a5f7ffb` Tests: only link against static libraries
|
||||
- `a16ad45...9cf7a3b` Lib: add support for EXTERNAL SASL method
|
||||
- `038a9ed` Lib: fix incorrect parameters to WSAPoll on Win32
|
||||
- `a240c69...14ae307` Lib: use non-blocking sockets internally
|
||||
- `8d1d5cc`, `5498dc6` Lib: simplify timer/timeout logic
|
||||
- `61fc4e1` Lib: add support for heartbeat checks in blocking send calls
|
||||
- `f462c0f...3546a70` Lib: Fix warnings on Win32
|
||||
- `ba9d8ba...112a54d` Lib: Add support for RabbitMQ auth failure extension
|
||||
- `fb8e318` Lib: allow calling functions to override client-properties
|
||||
- `3ef3f5f` examples: replace usleep() with nanosleep()
|
||||
- `9027a94` Lib: add AMQP_VERSION code
|
||||
- `9ee1718` Lib: fix res maybe returned uninitialized in amqp_merge_capbilities
|
||||
- `22a36db` Lib: Fix SSL_connection status check
|
||||
- `abbefd4` Lib: Fix issues with c89 compatiblity
|
||||
- `2bc1f9b...816cbfc` Lib: perf improvements when sending small messages by
|
||||
hinting to the OS message boundaries.
|
||||
- `be2e6dd...784a0e9` Lib: add select()-based timeout implementation
|
||||
- `91db548...8d77b4c` CI: add ubsan, asan, and tsan CI builds
|
||||
|
||||
## Changes since v0.5.2 (a.k.a., v0.6.0)
|
||||
- `e1746f9` Tools: Enable support for SSL in tools.
|
||||
- `9626dd5` Lib: ABI CHANGE: enable support for auto_delete, internal flags to
|
||||
amqp_exchange_declare
|
||||
- `ee54e27`, `656f833` Lib: check for double-close in SSL/TCP socket impl
|
||||
- `cf2760d` Lib: allocate struct when method has no field.
|
||||
- `513ad4a` Lib: add support for SANs in OpenSSL socket impl.
|
||||
- `5348c69` Lib: add functions to get negotiated frame_max and heartbeat parms.
|
||||
|
||||
## Changes since v0.5.1 (a.k.a., v0.5.2)
|
||||
- `fcdf0f8` Autoconf: check for htonll as declaration in a header file
|
||||
- `5790ec7` SSL: correctly report hostname verification errors.
|
||||
- `d60c28c` Build: disable OpenSSL deprecation warnings on OSX
|
||||
- `072191a` Lib: include platform, version and copyright in AMQP handshake
|
||||
- `8b448c6` Examples: print message body in amqp[s]_listen[q] examples
|
||||
- `7188e5d` Tools: Add flag to set prefetch for amqp-consume tool
|
||||
|
||||
## Changes since v0.5.0 (a.k.a., v0.5.1)
|
||||
### Enhancements:
|
||||
- `a566929` SSL: Add support for wildcards in hostname verification (Mike
|
||||
Steinert)
|
||||
- `a78aa8a` Lib: Use poll(2) instead of select(2) for timeouts on sockets.
|
||||
- `357bdb3` Lib: support for specifying frame and decoding pool sizes. (Mike
|
||||
Stitt)
|
||||
- `8956003` Lib: improve invalid frame detection code.
|
||||
|
||||
### Bug fixes:
|
||||
- `b852f84` Lib: Add missing amqp_get_server_properties() function.
|
||||
- `7001e82` Lib: Add missing ssize_t on Win32 (emazv72)
|
||||
- `c2ce2cb` Lib: Correctly specify WINVER on Win32 when unspecified.
|
||||
- `fe844e4` CMake: specify -DHAVE_CONFIG_H in examples.
|
||||
- `932de5f` Lib: correct time computation on Win32 (jestor)
|
||||
- `3e83192` HPUX: use gethrtime on HP-UX for timers.
|
||||
- `cb1b44e` HPUX: correct include location of sys/uio.h
|
||||
- `8ce585d` Lib: incorrect OOM condition when 0-lenth exchange name is received.
|
||||
- `c7716b8` CMake: correct htonll detection code on platforms defined with a
|
||||
macro.
|
||||
- `4dc4eda` Lib: remove unused assignment.
|
||||
- `45302cf` Lib: remove range-check of channel-ids.
|
||||
|
||||
|
||||
## Changes since v0.4.1 (a.k.a., v0.5.0):
|
||||
### Major changes:
|
||||
- Add amqp_get_broker_properties() function 5c7c40adc1
|
||||
- Remove distro-specific packaging a5749657ee
|
||||
- Add -x flag to amqp-consume utilty 1d9c5291ff
|
||||
- Add amqp_basic_nack() public API 9b168776fb
|
||||
- Add delivery mode constants to amqp.h 5f291ea772
|
||||
- Add support for connection.blocked/connection.unblocked methods ccbc24d270
|
||||
|
||||
### Bug fixes:
|
||||
- `f8c6cee749` Examples: Destroy amqp_envelope_t in consumer example
|
||||
- `ac88db56d3` CMake: fix generation of librabbitmq.pc
|
||||
- `d5b35afa40` CMake: fix missing POPT_INCLUDE_DIRS variable in tools/
|
||||
- `5ea6a0945a` build: provide independent locations for x64 libs
|
||||
- `fac34656c0` Doc: documentation fixes
|
||||
- `715901d675` Lib: Correct OpenSSL initialization under threaded conditions
|
||||
- `ce64e57df8` Examples: Handle unexpected frames in amqp_consumer.c
|
||||
- `bcda3e933d` CMake: Use GnuInstallDirs to generate install dirs
|
||||
- `27245a4e15` Lib: correctly handle amqp_get_monotonic_timestamp on win32
|
||||
- `693662ef5b` Tools: honor --persistent flag in publish utility
|
||||
- `01d9c3ca60` Doc: improve documentation in amqp_ssl_socket functions
|
||||
- `02d5c58ae4` autoconf: correct librabbitmq.pc generation
|
||||
- `1f4e0cc48b` Doc: improve documentation in amqp_tcp_socket functions
|
||||
|
||||
## Changes since v0.4.0:
|
||||
### Major changes:
|
||||
- Removed distro-specific packaging d285d01
|
||||
|
||||
### Bug fixes:
|
||||
- `a642602` FIX: destroy amqp_envelop_t object in consumer example
|
||||
- `860dd71` FIX: correct generation of librabbitmq.pc under CMake
|
||||
- `bdda7ab` FIX: amqp_socket_close() should not be exported from shlib
|
||||
- `24f4131` FIX: Use correct buf/len vars when re-starting send()
|
||||
|
||||
## Changes since v0.3.0:
|
||||
### New Features/Enhancements:
|
||||
- `amqp_login_with_properties()` function to connect to a broker sending a
|
||||
properties table to the broker 21b124e #101
|
||||
- SSL support (Mike Steinert) 473c865 #17
|
||||
- `amqp_simple_wait_frame_noblock()` function variant to wait for a frame
|
||||
with a timeout f8cfc72 #119
|
||||
- Allow memory to be released on a per-channel basis with
|
||||
`amqp_maybe_release_buffers_on_channel()` 4a2d899 #5
|
||||
- Support for AMQP heartbeats while blocking in `amqp_simple_wait_frame*()`
|
||||
and `amqp_basic_publish()` daa0e66 aca5dc1
|
||||
- `amqp_socket_open_noblock()` for a non-blocking socket connection
|
||||
(Bogdan Padalko) 6ad770d
|
||||
- `amqp_table_clone()` to do a deep-copy of an amqp_table_t 08af83a
|
||||
- Add option to listen to multiple keys in `amqp_consume` tool (Brian Hammond) e6c256d
|
||||
- Add contributed OpenVMS build system 448ab68
|
||||
- Higher level APIs for consuming messages 33ebeed #8
|
||||
- Doxygen-based API documentation.
|
||||
- Many improvements to error-handling and reporting
|
||||
|
||||
### Bug Fixes:
|
||||
- `24ffaf8` FIX: autotools was broken when dependency-tracking was disabled
|
||||
- `38e741b` FIX: CMake XmlTo not found warning
|
||||
- `906f04f` FIX: htonll redeclared on Win32 v8
|
||||
- `8e41603` FIX: SIGPIPE not disabled on OS X/BSD #102
|
||||
- `872ea49` FIX: Header issues with amqp.h on Mingw on Win32 (yoniyoni)
|
||||
- `0f1f75b` FIX: potential memory leak in amqp_new_connection
|
||||
- `c9f6312` FIX: missing va_end in `amqp_login()`/`amqp_login_with_properties()`
|
||||
- `7bb64e4` FIX: include amqp_tcp_socket.h in dpkg (Tim Stewart)
|
||||
- `ba9d1f5` FIX: Report out of buffer space in `amqp_table_encode()`
|
||||
- `9496e10` FIX: Remove `abort()` on invalid parameter in `amqp_send_frame()`
|
||||
- `f209420` FIX: Remote `abort()` in `amqp_simple_wait_method()`
|
||||
- `f027518` FIX: Return error on socket lib init error
|
||||
- `0ae534a` FIX: Correctly handle 0 return val from `SSL_read()`/`SSL_write()`
|
||||
- `22e41b8` FIX: Improve error handling in socket functions
|
||||
- `33c2353` FIX: Set state->socket to NULL after `amqp_socket_close()`
|
||||
- `c83e728` FIX: Incorrect error code returned
|
||||
- `1a19879` FIX: redecl of int i in `amqp_tcp_socket_writev()`
|
||||
- `7477449` FIX: incorrect bit-shift in `amqp_error_string2()`
|
||||
- `2e37bb3` FIX: correctly handle `amqp_get_sockfd()` in `amqp_simple_wait_frame()`
|
||||
- `52a459b` FIX: Don't delete state in `amqp_tune_connection()` on error
|
||||
- `01e38dd` FIX: Correctly handle `mach_timebase_info()` failure
|
||||
- `34bffb7` FIX: Correctly disable `SIGPIPE` on platforms with `SO_NOSIGPIPE`
|
||||
- `3866433` FIX: Use correct number of bits in timer precision on MacOSX
|
||||
- `b6a1dfe` FIX: Squash OpenSSL deprecated warnings on MacOSX (Bogdan Padalko)
|
||||
- `7a217d5` FIX: Incorrect `assert()` in `wait_frame_inner()`
|
||||
- `7942af3` FIX: Correctly handle 0-length table in `amqp_table_clone()`
|
||||
- `157788e` FIX: Correctly handle 0-length strings in `amqp_basic_properties_clone()`
|
||||
- `4eaf771` FIX: Correctly handle 0-length message body in `amqp_read_message()`
|
||||
- `59f943b` FIX: Double-free SSL on connection failure
|
||||
- `7a451a4` FIX: `amqp_open_socket()` not defined
|
|
@ -1,28 +0,0 @@
|
|||
Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
Alan Antonuk. All Rights Reserved.
|
||||
|
||||
Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
All Rights Reserved.
|
||||
|
||||
Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,128 +0,0 @@
|
|||
# RabbitMQ C AMQP client library
|
||||
|
||||
[](http://travis-ci.org/alanxz/rabbitmq-c)
|
||||
|
||||
[](https://coveralls.io/github/alanxz/rabbitmq-c?branch=master)
|
||||
|
||||
## Introduction
|
||||
|
||||
This is a C-language AMQP client library for use with v2.0+ of the
|
||||
[RabbitMQ](http://www.rabbitmq.com/) broker.
|
||||
|
||||
- <http://github.com/alanxz/rabbitmq-c>
|
||||
|
||||
Announcements regarding the library are periodically made on the
|
||||
rabbitmq-c-users and cross-posted to rabbitmq-users.
|
||||
|
||||
- <https://groups.google.com/forum/#!forum/rabbitmq-c-users>
|
||||
- <https://groups.google.com/forum/#!forum/rabbitmq-users>
|
||||
|
||||
## Latest Stable Version
|
||||
|
||||
The latest stable release of rabbitmq-c can be found at:
|
||||
|
||||
- <https://github.com/alanxz/rabbitmq-c/releases/latest>
|
||||
|
||||
## Documentation
|
||||
|
||||
API documentation for v0.8.0+ can viewed from:
|
||||
|
||||
<http://alanxz.github.io/rabbitmq-c/docs/0.8.0/>
|
||||
|
||||
## Getting started
|
||||
|
||||
### Building and installing
|
||||
|
||||
#### Prereqs:
|
||||
- [CMake v2.6 or better](http://www.cmake.org/)
|
||||
- A C compiler (GCC 4.4+, clang, and MSVC are test. Other compilers may also
|
||||
work)
|
||||
- *Optionally* [OpenSSL](http://www.openssl.org/) v0.9.8+ to enable support for
|
||||
connecting to RabbitMQ over SSL/TLS
|
||||
- *Optionally* [POpt](http://freecode.com/projects/popt) to build some handy
|
||||
command-line tools.
|
||||
- *Optionally* [XmlTo](https://fedorahosted.org/xmlto/) to build man pages for
|
||||
the handy command-line tools
|
||||
- *Optionally* [Doxygen](http://www.stack.nl/~dimitri/doxygen/) to build
|
||||
developer API documentation.
|
||||
|
||||
After downloading and extracting the source from a tarball to a directory
|
||||
([see above](#latest-stable-version)), the commands to build rabbitmq-c on most
|
||||
systems are:
|
||||
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
cmake --build [--config Release] .
|
||||
|
||||
The --config Release flag should be used in multi-configuration generators e.g.,
|
||||
Visual Studio or XCode.
|
||||
|
||||
It is also possible to point the CMake GUI tool at the CMakeLists.txt in the root of
|
||||
the source tree and generate build projects or IDE workspace
|
||||
|
||||
Installing the library and optionally specifying a prefix can be done with:
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
|
||||
cmake --build . [--config Release] --target install
|
||||
|
||||
More information on CMake can be found on its FAQ (http://www.cmake.org/Wiki/CMake_FAQ)
|
||||
|
||||
Other interesting flags that can be passed to CMake:
|
||||
|
||||
* `BUILD_EXAMPLES=ON/OFF` toggles building the examples. ON by default.
|
||||
* `BUILD_SHARED_LIBS=ON/OFF` toggles building rabbitmq-c as a shared library.
|
||||
ON by default.
|
||||
* `BUILD_STATIC_LIBS=ON/OFF` toggles building rabbitmq-c as a static library.
|
||||
OFF by default.
|
||||
* `BUILD_TESTS=ON/OFF` toggles building test code. ON by default.
|
||||
* `BUILD_TOOLS=ON/OFF` toggles building the command line tools. By default
|
||||
this is ON if the build system can find the POpt header and library.
|
||||
* `BUILD_TOOLS_DOCS=ON/OFF` toggles building the man pages for the command line
|
||||
tools. By default this is ON if BUILD_TOOLS is ON and the build system can
|
||||
find the XmlTo utility.
|
||||
* `ENABLE_SSL_SUPPORT=ON/OFF` toggles building rabbitmq-c with SSL support. By
|
||||
default this is ON if the OpenSSL headers and library can be found.
|
||||
* `BUILD_API_DOCS=ON/OFF` - toggles building the Doxygen API documentation, by
|
||||
default this is OFF
|
||||
|
||||
## Running the examples
|
||||
|
||||
Arrange for a RabbitMQ or other AMQP server to be running on
|
||||
`localhost` at TCP port number 5672.
|
||||
|
||||
In one terminal, run
|
||||
|
||||
./examples/amqp_listen localhost 5672 amq.direct test
|
||||
|
||||
In another terminal,
|
||||
|
||||
./examples/amqp_sendstring localhost 5672 amq.direct test "hello world"
|
||||
|
||||
You should see output similar to the following in the listener's
|
||||
terminal window:
|
||||
|
||||
Delivery 1, exchange amq.direct routingkey test
|
||||
Content-type: text/plain
|
||||
----
|
||||
00000000: 68 65 6C 6C 6F 20 77 6F : 72 6C 64 hello world
|
||||
0000000B:
|
||||
|
||||
## Writing applications using `librabbitmq`
|
||||
|
||||
Please see the `examples` directory for short examples of the use of
|
||||
the `librabbitmq` library.
|
||||
|
||||
### Threading
|
||||
|
||||
You cannot share a socket, an `amqp_connection_state_t`, or a channel
|
||||
between threads using `librabbitmq`. The `librabbitmq` library is
|
||||
built with event-driven, single-threaded applications in mind, and
|
||||
does not yet cater to any of the requirements of `pthread`ed
|
||||
applications.
|
||||
|
||||
Your applications instead should open an AMQP connection (and an
|
||||
associated socket, of course) per thread. If your program needs to
|
||||
access an AMQP connection or any of its channels from more than one
|
||||
thread, it is entirely responsible for designing and implementing an
|
||||
appropriate locking scheme. It will generally be much simpler to have
|
||||
a connection exclusive to each thread that needs AMQP service.
|
|
@ -1,8 +0,0 @@
|
|||
Thank-you to the following people for their contributions to the
|
||||
codebase:
|
||||
|
||||
- Scott Brooks / Epic Advertising <scott.brooks@epicadvertising.com>
|
||||
|
||||
- Frank Gönninger <frank.goenninger@consequor.de>
|
||||
|
||||
- Daniel Schauenberg <d@unwiredcouch.com>
|
|
@ -1,9 +0,0 @@
|
|||
Deal with version-mismatch-header received from the server
|
||||
|
||||
Cope with unknown frame types better. Currently it gets horribly
|
||||
confused about frame lengths.
|
||||
|
||||
Make client brutal by default, killing the program on any amqp
|
||||
error. Only if the user disables this behaviour will the user get to
|
||||
deal with error conditions themselves. Make use of amqp_rpc_reply
|
||||
consistent (i.e. universal), and rename it something like amqp_errno.
|
|
@ -1,34 +0,0 @@
|
|||
# appveyor configuration
|
||||
version: '{build}'
|
||||
|
||||
# Limit history cloned. This matches what travis-CI currently does.
|
||||
clone_depth: 50
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- GENERATOR: Visual Studio 12 Win64
|
||||
BITS: 64
|
||||
- GENERATOR: Visual Studio 12
|
||||
BITS: 32
|
||||
|
||||
cache:
|
||||
- c:\deps -> appveyor.yml
|
||||
|
||||
# borrowed from https://github.com/FreeTDS/freetds
|
||||
install:
|
||||
# xidel (xpath command line tool)
|
||||
- appveyor DownloadFile "https://downloads.sourceforge.net/project/videlibri/Xidel/Xidel 0.9.6/xidel-0.9.6.win32.zip"
|
||||
- 7z x xidel-0.9.6.win32.zip xidel.exe
|
||||
# detect version of Windows OpenSSL binaries published by the Shining Light Productions crew
|
||||
- xidel https://slproweb.com/products/Win32OpenSSL.html --extract "(//td/a[starts-with(@href, '/download') and starts-with(text(), 'Win32 OpenSSL') and ends-with(text(), 'Light')])[1]/translate(substring-before(substring-after(text(), 'Win32 OpenSSL v'), ' Light'), '.', '_')" > openssl_ver.txt
|
||||
- set /P OPENSSL_VER=< openssl_ver.txt
|
||||
# OpenSSL
|
||||
- appveyor DownloadFile https://slproweb.com/download/Win%BITS%OpenSSL-%OPENSSL_VER%.exe
|
||||
- "Win%BITS%OpenSSL-%OPENSSL_VER%.exe /SP- /SILENT /SUPPRESSMSGBOXES /NORESTART"
|
||||
|
||||
before_build:
|
||||
- cmake -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=ON -DBUILD_TESTS=ON -DENABLE_SSL_SUPPORT=True -G"%GENERATOR%" .
|
||||
|
||||
build:
|
||||
project: ALL_BUILD.vcxproj
|
||||
verbosity: normal
|
|
@ -1,103 +0,0 @@
|
|||
# This module defines two macros:
|
||||
# CMAKE_PUSH_CHECK_STATE()
|
||||
# and
|
||||
# CMAKE_POP_CHECK_STATE()
|
||||
# These two macros can be used to save and restore the state of the variables
|
||||
# CMAKE_REQUIRED_FLAGS, CMAKE_REQUIRED_DEFINITIONS, CMAKE_REQUIRED_LIBRARIES
|
||||
# and CMAKE_REQUIRED_INCLUDES used by the various Check-files coming with CMake,
|
||||
# like e.g. check_function_exists() etc.
|
||||
# The variable contents are pushed on a stack, pushing multiple times is supported.
|
||||
# This is useful e.g. when executing such tests in a Find-module, where they have to be set,
|
||||
# but after the Find-module has been executed they should have the same value
|
||||
# as they had before.
|
||||
#
|
||||
# Usage:
|
||||
# cmake_push_check_state()
|
||||
# set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -DSOME_MORE_DEF)
|
||||
# check_function_exists(...)
|
||||
# cmake_pop_check_state()
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2006-2011 Alexander Neundorf, <neundorf@kde.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * 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 copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# * Neither the names of Kitware, Inc., the Insight Software Consortium,
|
||||
# nor the names of their contributors may be used to endorse or promote
|
||||
# products derived from this software without specific prior written
|
||||
# permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
#
|
||||
# The above copyright and license notice applies to distributions of
|
||||
# CMake in source and binary form. Some source files contain additional
|
||||
# notices of original copyright by their contributors; see each source
|
||||
# for details. Third-party software packages supplied with CMake under
|
||||
# compatible licenses provide their own copyright notices documented in
|
||||
# corresponding subdirectories.
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
#
|
||||
# CMake was initially developed by Kitware with the following sponsorship:
|
||||
#
|
||||
# * National Library of Medicine at the National Institutes of Health
|
||||
# as part of the Insight Segmentation and Registration Toolkit (ITK).
|
||||
#
|
||||
# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
|
||||
# Visualization Initiative.
|
||||
#
|
||||
# * National Alliance for Medical Image Computing (NAMIC) is funded by the
|
||||
# National Institutes of Health through the NIH Roadmap for Medical Research,
|
||||
# Grant U54 EB005149.
|
||||
#
|
||||
# * Kitware, Inc.
|
||||
|
||||
macro(CMAKE_PUSH_CHECK_STATE)
|
||||
|
||||
if(NOT DEFINED _CMAKE_PUSH_CHECK_STATE_COUNTER)
|
||||
set(_CMAKE_PUSH_CHECK_STATE_COUNTER 0)
|
||||
endif()
|
||||
|
||||
math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}+1")
|
||||
|
||||
set(_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_INCLUDES})
|
||||
set(_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_DEFINITIONS})
|
||||
set(_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LIBRARIES})
|
||||
set(_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_FLAGS})
|
||||
endmacro()
|
||||
|
||||
macro(CMAKE_POP_CHECK_STATE)
|
||||
|
||||
# don't pop more than we pushed
|
||||
if("${_CMAKE_PUSH_CHECK_STATE_COUNTER}" GREATER "0")
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
|
||||
set(CMAKE_REQUIRED_DEFINITIONS ${_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
|
||||
set(CMAKE_REQUIRED_FLAGS ${_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
|
||||
|
||||
math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}-1")
|
||||
endif()
|
||||
|
||||
endmacro()
|
|
@ -1,22 +0,0 @@
|
|||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,39 +0,0 @@
|
|||
# - Try to find the popt options processing library
|
||||
# The module will set the following variables
|
||||
#
|
||||
# POPT_FOUND - System has popt
|
||||
# POPT_INCLUDE_DIR - The popt include directory
|
||||
# POPT_LIBRARY - The libraries needed to use popt
|
||||
|
||||
# use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_search_module(PC_POPT QUIET popt)
|
||||
endif ()
|
||||
|
||||
# Find the include directories
|
||||
FIND_PATH(POPT_INCLUDE_DIR
|
||||
NAMES popt.h
|
||||
HINTS
|
||||
${PC_POPT_INCLUDEDIR}
|
||||
${PC_POPT_INCLUDE_DIRS}
|
||||
DOC "Path containing the popt.h include file"
|
||||
)
|
||||
|
||||
FIND_LIBRARY(POPT_LIBRARY
|
||||
NAMES popt
|
||||
HINTS
|
||||
${PC_POPT_LIBRARYDIR}
|
||||
${PC_POPT_LIBRARY_DIRS}
|
||||
DOC "popt library path"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(POPT
|
||||
REQUIRED_VARS POPT_INCLUDE_DIR POPT_LIBRARY
|
||||
VERSION_VAR PC_POPT_VERSION)
|
||||
|
||||
MARK_AS_ADVANCED(POPT_INCLUDE_DIR POPT_LIBRARY)
|
|
@ -1,98 +0,0 @@
|
|||
# - Convert XML docBook files to various formats
|
||||
# This will convert XML docBook files to various formats like:
|
||||
# man html txt dvi ps pdf
|
||||
# macro XMLTO(outfiles infiles... MODES modes...)
|
||||
|
||||
find_program ( XMLTO_EXECUTABLE
|
||||
NAMES xmlto
|
||||
DOC "path to the xmlto docbook xslt frontend"
|
||||
)
|
||||
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(XMLTO
|
||||
REQUIRED_VARS XMLTO_EXECUTABLE)
|
||||
|
||||
mark_as_advanced( XMLTO_EXECUTABLE )
|
||||
|
||||
macro ( _XMLTO_FILE outfiles mode)
|
||||
#special settings
|
||||
set ( XMLTO_FILEEXT_man 1 )
|
||||
set ( XMLTO_MODE_html xhtml-nochunks )
|
||||
|
||||
if ( NOT XMLTO_MODE_${mode})
|
||||
set ( XMLTO_MODE_${mode} ${mode} )
|
||||
endif ( NOT XMLTO_MODE_${mode} )
|
||||
if ( NOT XMLTO_FILEEXT_${mode} )
|
||||
set ( XMLTO_FILEEXT_${mode} ${mode} )
|
||||
endif ( NOT XMLTO_FILEEXT_${mode} )
|
||||
|
||||
foreach ( dbFile ${ARGN} )
|
||||
#TODO: set XMLTO_FILEEXT_man to value from <manvolnum>
|
||||
if ( "${mode}" STREQUAL "man" )
|
||||
file ( READ "${dbFile}" _DB_FILE_CONTENTS )
|
||||
string ( REGEX MATCH "<manvolnum>[^<]*" XMLTO_FILEEXT_${mode} "${_DB_FILE_CONTENTS}" )
|
||||
string ( REGEX REPLACE "^<manvolnum>" "" XMLTO_FILEEXT_${mode} "${XMLTO_FILEEXT_${mode}}" )
|
||||
string ( REGEX REPLACE "[[:space:]]" "" XMLTO_FILEEXT_${mode} "${XMLTO_FILEEXT_${mode}}" )
|
||||
endif ( "${mode}" STREQUAL "man" )
|
||||
|
||||
get_filename_component ( dbFilePath ${CMAKE_CURRENT_BINARY_DIR}/${dbFile} PATH )
|
||||
get_filename_component ( dbFileWE ${dbFile} NAME_WE )
|
||||
get_filename_component ( dbFileAbsWE ${dbFilePath}/${dbFileWE} ABSOLUTE )
|
||||
|
||||
add_custom_command (
|
||||
OUTPUT ${dbFileAbsWE}.${XMLTO_FILEEXT_${mode}}
|
||||
COMMAND ${XMLTO_EXECUTABLE} ${XMLTO_COMMAND_ARGS} -o ${dbFilePath}
|
||||
${XMLTO_MODE_${mode}} "${CMAKE_CURRENT_SOURCE_DIR}/${dbFile}"
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/${dbFile}
|
||||
DEPENDS ${XMLTO_DEPENDS}
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
set ( ${outfiles}
|
||||
${${outfiles}}
|
||||
${dbFileAbsWE}.${XMLTO_FILEEXT_${mode}}
|
||||
)
|
||||
endforeach ( dbFile )
|
||||
endmacro ( _XMLTO_FILE outfiles )
|
||||
|
||||
macro ( XMLTO )
|
||||
set ( XMLTO_MODES )
|
||||
set ( XMLTO_FILES )
|
||||
set ( XMLTO_HAS_MODES false )
|
||||
set ( XMLTO_ADD_DEFAULT false )
|
||||
foreach ( arg ${ARGN} )
|
||||
if ( ${arg} STREQUAL "MODES" )
|
||||
set ( XMLTO_HAS_MODES true )
|
||||
elseif ( ${arg} STREQUAL "ALL" )
|
||||
set ( XMLTO_ADD_DEFAULT true )
|
||||
else ( ${arg} STREQUAL "MODES" )
|
||||
if ( XMLTO_HAS_MODES )
|
||||
set ( XMLTO_MODES ${XMLTO_MODES} ${arg} )
|
||||
else ( XMLTO_HAS_MODES )
|
||||
set ( XMLTO_FILES ${XMLTO_FILES} ${arg} )
|
||||
endif ( XMLTO_HAS_MODES )
|
||||
endif ( ${arg} STREQUAL "MODES" )
|
||||
endforeach ( arg ${ARGN} )
|
||||
if ( NOT XMLTO_MODES )
|
||||
set ( XMLTO_MODES html )
|
||||
endif ( NOT XMLTO_MODES )
|
||||
|
||||
foreach ( mode ${XMLTO_MODES} )
|
||||
_xmlto_file ( XMLTO_FILES_${mode} ${mode} ${XMLTO_FILES} )
|
||||
if ( XMLTO_ADD_DEFAULT )
|
||||
add_custom_target ( ${mode} ALL
|
||||
DEPENDS ${XMLTO_FILES_${mode}}
|
||||
VERBATIM
|
||||
)
|
||||
else ( XMLTO_ADD_DEFAULT )
|
||||
add_custom_target ( ${mode}
|
||||
DEPENDS ${XMLTO_FILES_${mode}}
|
||||
VERBATIM
|
||||
)
|
||||
endif ( XMLTO_ADD_DEFAULT )
|
||||
endforeach ( mode )
|
||||
|
||||
set ( XMLTO_MODES )
|
||||
set ( XMLTO_FILES )
|
||||
endmacro ( XMLTO )
|
|
@ -1,205 +0,0 @@
|
|||
#.rst:
|
||||
# GNUInstallDirs
|
||||
# --------------
|
||||
#
|
||||
# Define GNU standard installation directories
|
||||
#
|
||||
# Provides install directory variables as defined for GNU software:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
|
||||
#
|
||||
# Inclusion of this module defines the following variables:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# CMAKE_INSTALL_<dir> - destination for files of a given type
|
||||
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
|
||||
#
|
||||
# where <dir> is one of:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# BINDIR - user executables (bin)
|
||||
# SBINDIR - system admin executables (sbin)
|
||||
# LIBEXECDIR - program executables (libexec)
|
||||
# SYSCONFDIR - read-only single-machine data (etc)
|
||||
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
|
||||
# LOCALSTATEDIR - modifiable single-machine data (var)
|
||||
# LIBDIR - object code libraries (lib or lib64 or lib/<multiarch-tuple> on Debian)
|
||||
# INCLUDEDIR - C header files (include)
|
||||
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
|
||||
# DATAROOTDIR - read-only architecture-independent data root (share)
|
||||
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
|
||||
# INFODIR - info documentation (DATAROOTDIR/info)
|
||||
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
|
||||
# MANDIR - man documentation (DATAROOTDIR/man)
|
||||
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
|
||||
#
|
||||
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION
|
||||
# options of install() commands for the corresponding file type. If the
|
||||
# includer does not define a value the above-shown default will be used
|
||||
# and the value will appear in the cache for editing by the user. Each
|
||||
# CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
|
||||
# from the corresponding destination by prepending (if necessary) the
|
||||
# value of CMAKE_INSTALL_PREFIX.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
|
||||
# Copyright 2011 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# Installation directories
|
||||
#
|
||||
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
|
||||
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
|
||||
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
|
||||
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
|
||||
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
|
||||
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
|
||||
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||
set(_LIBDIR_DEFAULT "lib")
|
||||
# Override this default 'lib' with 'lib64' iff:
|
||||
# - we are on Linux system but NOT cross-compiling
|
||||
# - we are NOT on debian
|
||||
# - we are on a 64 bits system
|
||||
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
|
||||
# For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
|
||||
# CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
|
||||
# See http://wiki.debian.org/Multiarch
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
|
||||
AND NOT CMAKE_CROSSCOMPILING)
|
||||
if (EXISTS "/etc/debian_version") # is this a debian system ?
|
||||
if(CMAKE_LIBRARY_ARCHITECTURE)
|
||||
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
|
||||
endif()
|
||||
else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
|
||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
||||
message(AUTHOR_WARNING
|
||||
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
|
||||
"Please enable at least one language before including GNUInstallDirs.")
|
||||
else()
|
||||
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(_LIBDIR_DEFAULT "lib64")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
|
||||
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
|
||||
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
|
||||
# the cache and store the defaults in local variables if the cache values are
|
||||
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
|
||||
|
||||
if(NOT CMAKE_INSTALL_DATADIR)
|
||||
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
|
||||
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_INFODIR)
|
||||
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
|
||||
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_LOCALEDIR)
|
||||
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
|
||||
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_MANDIR)
|
||||
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
|
||||
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_DOCDIR)
|
||||
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
|
||||
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
mark_as_advanced(
|
||||
CMAKE_INSTALL_BINDIR
|
||||
CMAKE_INSTALL_SBINDIR
|
||||
CMAKE_INSTALL_LIBEXECDIR
|
||||
CMAKE_INSTALL_SYSCONFDIR
|
||||
CMAKE_INSTALL_SHAREDSTATEDIR
|
||||
CMAKE_INSTALL_LOCALSTATEDIR
|
||||
CMAKE_INSTALL_LIBDIR
|
||||
CMAKE_INSTALL_INCLUDEDIR
|
||||
CMAKE_INSTALL_OLDINCLUDEDIR
|
||||
CMAKE_INSTALL_DATAROOTDIR
|
||||
CMAKE_INSTALL_DATADIR
|
||||
CMAKE_INSTALL_INFODIR
|
||||
CMAKE_INSTALL_LOCALEDIR
|
||||
CMAKE_INSTALL_MANDIR
|
||||
CMAKE_INSTALL_DOCDIR
|
||||
)
|
||||
|
||||
# Result directories
|
||||
#
|
||||
foreach(dir
|
||||
BINDIR
|
||||
SBINDIR
|
||||
LIBEXECDIR
|
||||
SYSCONFDIR
|
||||
SHAREDSTATEDIR
|
||||
LOCALSTATEDIR
|
||||
LIBDIR
|
||||
INCLUDEDIR
|
||||
OLDINCLUDEDIR
|
||||
DATAROOTDIR
|
||||
DATADIR
|
||||
INFODIR
|
||||
LOCALEDIR
|
||||
MANDIR
|
||||
DOCDIR
|
||||
)
|
||||
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
|
||||
endif()
|
||||
endforeach()
|
|
@ -1,28 +0,0 @@
|
|||
#Inspired from http://www.cmake.org/Wiki/CMakeTestInline
|
||||
|
||||
IF(NOT DEFINED C_INLINE_KEYWORD)
|
||||
|
||||
SET(INLINE_TEST_SRC "/* Inspired by autoconf's c.m4 */
|
||||
static inline int static_foo() {return 0\;}
|
||||
int main(int argc, char *argv[]){return 0\;}
|
||||
")
|
||||
|
||||
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/CMakeTestCInline.c ${INLINE_TEST_SRC})
|
||||
|
||||
FOREACH(KEYWORD "inline" "__inline__" "__inline")
|
||||
IF(NOT DEFINED C_INLINE)
|
||||
TRY_COMPILE(C_HAS_${KEYWORD}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/CMakeTestCInline.c
|
||||
COMPILE_DEFINITIONS "-Dinline=${KEYWORD}"
|
||||
)
|
||||
IF(C_HAS_${KEYWORD})
|
||||
SET(C_INLINE ${KEYWORD})
|
||||
ENDIF(C_HAS_${KEYWORD})
|
||||
ENDIF(NOT DEFINED C_INLINE)
|
||||
ENDFOREACH(KEYWORD)
|
||||
|
||||
SET(C_INLINE_KEYWORD ${C_INLINE} CACHE INTERNAL "The keyword needed by the C compiler to inline a function" FORCE)
|
||||
message(STATUS "Found C inline keyword: ${C_INLINE_KEYWORD}")
|
||||
|
||||
ENDIF(NOT DEFINED C_INLINE_KEYWORD)
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
# define inline ${C_INLINE_KEYWORD}
|
||||
#endif
|
||||
|
||||
#cmakedefine HAVE_SELECT
|
||||
|
||||
#cmakedefine HAVE_POLL
|
||||
|
||||
#define AMQ_PLATFORM "@CMAKE_SYSTEM@"
|
||||
|
||||
#endif /* CONFIG_H */
|
|
@ -1,17 +0,0 @@
|
|||
/* Functions to help coverity do static analysis on rabbitmq-c */
|
||||
|
||||
typedef struct {
|
||||
} amqp_rpc_reply_t;
|
||||
|
||||
/* librabbitmq/amqp_private.h */
|
||||
void amqp_abort(const char* fmt, ...) { __coverity_panic__(); }
|
||||
|
||||
/* tools/common.h */
|
||||
void die(const char* fmt, ...) { __coverity_panic__(); }
|
||||
void die_errno(int err, const char* fmt, ...) { __coverity_panic__(); }
|
||||
void die_amqp_error(int err, const char* fmt, ...) { __coverity_panic__(); }
|
||||
void die_rpc(amqp_rpc_reply_t r, const char* fmt, ...) { __coverity_panic__(); }
|
||||
|
||||
/* examples/utils.h */
|
||||
void die_on_amqp_error(amqp_rpc_reply_t* r) { __coverity_panic__(); }
|
||||
void die_on_error(int r) { __coverity_panic__(); }
|
|
@ -1,317 +0,0 @@
|
|||
# Doxyfile 1.8.4
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = rabbitmq-c
|
||||
PROJECT_NUMBER = @VERSION@
|
||||
PROJECT_BRIEF = "C AMQP Client library for RabbitMQ"
|
||||
PROJECT_LOGO =
|
||||
OUTPUT_DIRECTORY = .
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF =
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 2
|
||||
ALIASES =
|
||||
TCL_SUBST =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
EXTENSION_MAPPING =
|
||||
MARKDOWN_SUPPORT = YES
|
||||
AUTOLINK_SUPPORT = YES
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
INLINE_GROUPED_CLASSES = NO
|
||||
INLINE_SIMPLE_STRUCTS = NO
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_PACKAGE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = NO
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
STRICT_PROTO_MATCHING = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
CITE_BIB_FILES =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = @CMAKE_CURRENT_SOURCE_DIR@/README.md \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/ChangeLog.md \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/librabbitmq \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/docs
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.h \
|
||||
*.md
|
||||
RECURSIVE = NO
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS = amqp_private.h \
|
||||
config.h
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH = @CMAKE_CURRENT_SOURCE_DIR@ \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/examples
|
||||
EXAMPLE_PATTERNS = *.c \
|
||||
*.md
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
FILTER_SOURCE_PATTERNS =
|
||||
USE_MDFILE_AS_MAINPAGE = README.md
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX = amqp_
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
HTML_EXTRA_FILES =
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
HTML_COLORSTYLE_SAT = 100
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
HTML_TIMESTAMP = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||
DOCSET_PUBLISHER_NAME = Publisher
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE = org.doxygen.Project
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||
DISABLE_INDEX = NO
|
||||
GENERATE_TREEVIEW = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
TREEVIEW_WIDTH = 250
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_FORMAT = HTML-CSS
|
||||
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
|
||||
MATHJAX_EXTENSIONS =
|
||||
MATHJAX_CODEFILE =
|
||||
SEARCHENGINE = YES
|
||||
SERVER_BASED_SEARCH = NO
|
||||
EXTERNAL_SEARCH = NO
|
||||
SEARCHENGINE_URL =
|
||||
SEARCHDATA_FILE = searchdata.xml
|
||||
EXTERNAL_SEARCH_ID =
|
||||
EXTRA_SEARCH_MAPPINGS =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
LATEX_FOOTER =
|
||||
LATEX_EXTRA_FILES =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
LATEX_BIB_STYLE = plain
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the DOCBOOK output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_DOCBOOK = NO
|
||||
DOCBOOK_OUTPUT = docbook
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/librabbitmq \
|
||||
@CMAKE_CURRENT_BINARY_DIR@/librabbitmq
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = AMQP_BEGIN_DECLS= \
|
||||
AMQP_END_DECLS= \
|
||||
AMQP_PUBLIC_FUNCTION= \
|
||||
AMQP_PUBLIC_VARIABLE= \
|
||||
AMQP_CALL= \
|
||||
AMQP_DEPRECATED(x)=x
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
EXTERNAL_PAGES = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
DOT_NUM_THREADS = 0
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
INTERACTIVE_SVG = NO
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MSCFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
|
@ -1,52 +0,0 @@
|
|||
if (NOT BUILD_SHARED_LIBS)
|
||||
add_definitions(-DAMQP_STATIC)
|
||||
endif()
|
||||
|
||||
include_directories(${LIBRABBITMQ_INCLUDE_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
set(PLATFORM_DIR win32)
|
||||
else (WIN32)
|
||||
set(PLATFORM_DIR unix)
|
||||
endif (WIN32)
|
||||
|
||||
set(COMMON_SRCS
|
||||
utils.h
|
||||
utils.c
|
||||
${PLATFORM_DIR}/platform_utils.c
|
||||
)
|
||||
|
||||
add_executable(amqp_sendstring amqp_sendstring.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_sendstring ${RMQ_LIBRARY_TARGET})
|
||||
|
||||
add_executable(amqp_rpc_sendstring_client amqp_rpc_sendstring_client.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_rpc_sendstring_client ${RMQ_LIBRARY_TARGET})
|
||||
|
||||
add_executable(amqp_exchange_declare amqp_exchange_declare.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_exchange_declare ${RMQ_LIBRARY_TARGET})
|
||||
|
||||
add_executable(amqp_listen amqp_listen.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_listen ${RMQ_LIBRARY_TARGET})
|
||||
|
||||
add_executable(amqp_producer amqp_producer.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_producer ${RMQ_LIBRARY_TARGET})
|
||||
|
||||
add_executable(amqp_connect_timeout amqp_connect_timeout.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_connect_timeout ${RMQ_LIBRARY_TARGET})
|
||||
|
||||
add_executable(amqp_consumer amqp_consumer.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_consumer ${RMQ_LIBRARY_TARGET})
|
||||
|
||||
add_executable(amqp_unbind amqp_unbind.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_unbind ${RMQ_LIBRARY_TARGET})
|
||||
|
||||
add_executable(amqp_bind amqp_bind.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_bind ${RMQ_LIBRARY_TARGET})
|
||||
|
||||
add_executable(amqp_listenq amqp_listenq.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_listenq ${RMQ_LIBRARY_TARGET})
|
||||
|
||||
if (ENABLE_SSL_SUPPORT)
|
||||
add_executable(amqp_ssl_connect amqp_ssl_connect.c ${COMMON_SRCS})
|
||||
target_link_libraries(amqp_ssl_connect ${RMQ_LIBRARY_TARGET})
|
||||
endif (ENABLE_SSL_SUPPORT)
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
int main(int argc, char const *const *argv) {
|
||||
char const *hostname;
|
||||
int port, status;
|
||||
char const *exchange;
|
||||
char const *bindingkey;
|
||||
char const *queue;
|
||||
amqp_socket_t *socket = NULL;
|
||||
amqp_connection_state_t conn;
|
||||
|
||||
if (argc < 6) {
|
||||
fprintf(stderr, "Usage: amqp_bind host port exchange bindingkey queue\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
exchange = argv[3];
|
||||
bindingkey = argv[4];
|
||||
queue = argv[5];
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating TCP socket");
|
||||
}
|
||||
|
||||
status = amqp_socket_open(socket, hostname, port);
|
||||
if (status) {
|
||||
die("opening TCP socket");
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
amqp_channel_open(conn, 1);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
|
||||
|
||||
amqp_queue_bind(conn, 1, amqp_cstring_bytes(queue),
|
||||
amqp_cstring_bytes(exchange), amqp_cstring_bytes(bindingkey),
|
||||
amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Unbinding");
|
||||
|
||||
die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
|
||||
"Closing channel");
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
return 0;
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by Bogdan Padalko are Copyright (c) 2013.
|
||||
* Bogdan Padalko. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Winsock2.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
int main(int argc, char const *const *argv) {
|
||||
char const *hostname;
|
||||
int port;
|
||||
amqp_socket_t *socket;
|
||||
amqp_connection_state_t conn;
|
||||
struct timeval tval;
|
||||
struct timeval *tv;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr,
|
||||
"Usage: amqp_connect_timeout host port [timeout_sec "
|
||||
"[timeout_usec=0]]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
tv = &tval;
|
||||
|
||||
tv->tv_sec = atoi(argv[3]);
|
||||
|
||||
if (argc > 4) {
|
||||
tv->tv_usec = atoi(argv[4]);
|
||||
} else {
|
||||
tv->tv_usec = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
tv = NULL;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
|
||||
if (!socket) {
|
||||
die("creating TCP socket");
|
||||
}
|
||||
|
||||
die_on_error(amqp_socket_open_noblock(socket, hostname, port, tv),
|
||||
"opening TCP socket");
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
|
||||
printf("Done\n");
|
||||
return 0;
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define SUMMARY_EVERY_US 1000000
|
||||
|
||||
static void run(amqp_connection_state_t conn) {
|
||||
uint64_t start_time = now_microseconds();
|
||||
int received = 0;
|
||||
int previous_received = 0;
|
||||
uint64_t previous_report_time = start_time;
|
||||
uint64_t next_summary_time = start_time + SUMMARY_EVERY_US;
|
||||
|
||||
amqp_frame_t frame;
|
||||
|
||||
uint64_t now;
|
||||
|
||||
for (;;) {
|
||||
amqp_rpc_reply_t ret;
|
||||
amqp_envelope_t envelope;
|
||||
|
||||
now = now_microseconds();
|
||||
if (now > next_summary_time) {
|
||||
int countOverInterval = received - previous_received;
|
||||
double intervalRate =
|
||||
countOverInterval / ((now - previous_report_time) / 1000000.0);
|
||||
printf("%d ms: Received %d - %d since last report (%d Hz)\n",
|
||||
(int)(now - start_time) / 1000, received, countOverInterval,
|
||||
(int)intervalRate);
|
||||
|
||||
previous_received = received;
|
||||
previous_report_time = now;
|
||||
next_summary_time += SUMMARY_EVERY_US;
|
||||
}
|
||||
|
||||
amqp_maybe_release_buffers(conn);
|
||||
ret = amqp_consume_message(conn, &envelope, NULL, 0);
|
||||
|
||||
if (AMQP_RESPONSE_NORMAL != ret.reply_type) {
|
||||
if (AMQP_RESPONSE_LIBRARY_EXCEPTION == ret.reply_type &&
|
||||
AMQP_STATUS_UNEXPECTED_STATE == ret.library_error) {
|
||||
if (AMQP_STATUS_OK != amqp_simple_wait_frame(conn, &frame)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (AMQP_FRAME_METHOD == frame.frame_type) {
|
||||
switch (frame.payload.method.id) {
|
||||
case AMQP_BASIC_ACK_METHOD:
|
||||
/* if we've turned publisher confirms on, and we've published a
|
||||
* message here is a message being confirmed.
|
||||
*/
|
||||
break;
|
||||
case AMQP_BASIC_RETURN_METHOD:
|
||||
/* if a published message couldn't be routed and the mandatory
|
||||
* flag was set this is what would be returned. The message then
|
||||
* needs to be read.
|
||||
*/
|
||||
{
|
||||
amqp_message_t message;
|
||||
ret = amqp_read_message(conn, frame.channel, &message, 0);
|
||||
if (AMQP_RESPONSE_NORMAL != ret.reply_type) {
|
||||
return;
|
||||
}
|
||||
|
||||
amqp_destroy_message(&message);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AMQP_CHANNEL_CLOSE_METHOD:
|
||||
/* a channel.close method happens when a channel exception occurs,
|
||||
* this can happen by publishing to an exchange that doesn't exist
|
||||
* for example.
|
||||
*
|
||||
* In this case you would need to open another channel redeclare
|
||||
* any queues that were declared auto-delete, and restart any
|
||||
* consumers that were attached to the previous channel.
|
||||
*/
|
||||
return;
|
||||
|
||||
case AMQP_CONNECTION_CLOSE_METHOD:
|
||||
/* a connection.close method happens when a connection exception
|
||||
* occurs, this can happen by trying to use a channel that isn't
|
||||
* open for example.
|
||||
*
|
||||
* In this case the whole connection must be restarted.
|
||||
*/
|
||||
return;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "An unexpected method was received %u\n",
|
||||
frame.payload.method.id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
amqp_destroy_envelope(&envelope);
|
||||
}
|
||||
|
||||
received++;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char const *const *argv) {
|
||||
char const *hostname;
|
||||
int port, status;
|
||||
char const *exchange;
|
||||
char const *bindingkey;
|
||||
amqp_socket_t *socket = NULL;
|
||||
amqp_connection_state_t conn;
|
||||
|
||||
amqp_bytes_t queuename;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: amqp_consumer host port\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
exchange = "amq.direct"; /* argv[3]; */
|
||||
bindingkey = "test queue"; /* argv[4]; */
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating TCP socket");
|
||||
}
|
||||
|
||||
status = amqp_socket_open(socket, hostname, port);
|
||||
if (status) {
|
||||
die("opening TCP socket");
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
amqp_channel_open(conn, 1);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
|
||||
|
||||
{
|
||||
amqp_queue_declare_ok_t *r = amqp_queue_declare(
|
||||
conn, 1, amqp_empty_bytes, 0, 0, 0, 1, amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Declaring queue");
|
||||
queuename = amqp_bytes_malloc_dup(r->queue);
|
||||
if (queuename.bytes == NULL) {
|
||||
fprintf(stderr, "Out of memory while copying queue name");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
amqp_queue_bind(conn, 1, queuename, amqp_cstring_bytes(exchange),
|
||||
amqp_cstring_bytes(bindingkey), amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Binding queue");
|
||||
|
||||
amqp_basic_consume(conn, 1, queuename, amqp_empty_bytes, 0, 1, 0,
|
||||
amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming");
|
||||
|
||||
run(conn);
|
||||
|
||||
die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
|
||||
"Closing channel");
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
int main(int argc, char const *const *argv) {
|
||||
char const *hostname;
|
||||
int port, status;
|
||||
char const *exchange;
|
||||
char const *exchangetype;
|
||||
amqp_socket_t *socket = NULL;
|
||||
amqp_connection_state_t conn;
|
||||
|
||||
if (argc < 5) {
|
||||
fprintf(stderr,
|
||||
"Usage: amqp_exchange_declare host port exchange exchangetype\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
exchange = argv[3];
|
||||
exchangetype = argv[4];
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating TCP socket");
|
||||
}
|
||||
|
||||
status = amqp_socket_open(socket, hostname, port);
|
||||
if (status) {
|
||||
die("opening TCP socket");
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
amqp_channel_open(conn, 1);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
|
||||
|
||||
amqp_exchange_declare(conn, 1, amqp_cstring_bytes(exchange),
|
||||
amqp_cstring_bytes(exchangetype), 0, 0, 0, 0,
|
||||
amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Declaring exchange");
|
||||
|
||||
die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
|
||||
"Closing channel");
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
return 0;
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
int main(int argc, char const *const *argv) {
|
||||
char const *hostname;
|
||||
int port, status;
|
||||
char const *exchange;
|
||||
char const *bindingkey;
|
||||
amqp_socket_t *socket = NULL;
|
||||
amqp_connection_state_t conn;
|
||||
|
||||
amqp_bytes_t queuename;
|
||||
|
||||
if (argc < 5) {
|
||||
fprintf(stderr, "Usage: amqp_listen host port exchange bindingkey\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
exchange = argv[3];
|
||||
bindingkey = argv[4];
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating TCP socket");
|
||||
}
|
||||
|
||||
status = amqp_socket_open(socket, hostname, port);
|
||||
if (status) {
|
||||
die("opening TCP socket");
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
amqp_channel_open(conn, 1);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
|
||||
|
||||
{
|
||||
amqp_queue_declare_ok_t *r = amqp_queue_declare(
|
||||
conn, 1, amqp_empty_bytes, 0, 0, 0, 1, amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Declaring queue");
|
||||
queuename = amqp_bytes_malloc_dup(r->queue);
|
||||
if (queuename.bytes == NULL) {
|
||||
fprintf(stderr, "Out of memory while copying queue name");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
amqp_queue_bind(conn, 1, queuename, amqp_cstring_bytes(exchange),
|
||||
amqp_cstring_bytes(bindingkey), amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Binding queue");
|
||||
|
||||
amqp_basic_consume(conn, 1, queuename, amqp_empty_bytes, 0, 1, 0,
|
||||
amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming");
|
||||
|
||||
{
|
||||
for (;;) {
|
||||
amqp_rpc_reply_t res;
|
||||
amqp_envelope_t envelope;
|
||||
|
||||
amqp_maybe_release_buffers(conn);
|
||||
|
||||
res = amqp_consume_message(conn, &envelope, NULL, 0);
|
||||
|
||||
if (AMQP_RESPONSE_NORMAL != res.reply_type) {
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Delivery %u, exchange %.*s routingkey %.*s\n",
|
||||
(unsigned)envelope.delivery_tag, (int)envelope.exchange.len,
|
||||
(char *)envelope.exchange.bytes, (int)envelope.routing_key.len,
|
||||
(char *)envelope.routing_key.bytes);
|
||||
|
||||
if (envelope.message.properties._flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
|
||||
printf("Content-type: %.*s\n",
|
||||
(int)envelope.message.properties.content_type.len,
|
||||
(char *)envelope.message.properties.content_type.bytes);
|
||||
}
|
||||
printf("----\n");
|
||||
|
||||
amqp_dump(envelope.message.body.bytes, envelope.message.body.len);
|
||||
|
||||
amqp_destroy_envelope(&envelope);
|
||||
}
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
|
||||
"Closing channel");
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
int main(int argc, char const *const *argv) {
|
||||
char const *hostname;
|
||||
int port, status;
|
||||
char const *queuename;
|
||||
amqp_socket_t *socket = NULL;
|
||||
amqp_connection_state_t conn;
|
||||
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "Usage: amqp_listenq host port queuename\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
queuename = argv[3];
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating TCP socket");
|
||||
}
|
||||
|
||||
status = amqp_socket_open(socket, hostname, port);
|
||||
if (status) {
|
||||
die("opening TCP socket");
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
amqp_channel_open(conn, 1);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
|
||||
|
||||
amqp_basic_consume(conn, 1, amqp_cstring_bytes(queuename), amqp_empty_bytes,
|
||||
0, 0, 0, amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming");
|
||||
|
||||
for (;;) {
|
||||
amqp_rpc_reply_t res;
|
||||
amqp_envelope_t envelope;
|
||||
|
||||
amqp_maybe_release_buffers(conn);
|
||||
|
||||
res = amqp_consume_message(conn, &envelope, NULL, 0);
|
||||
|
||||
if (AMQP_RESPONSE_NORMAL != res.reply_type) {
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Delivery %u, exchange %.*s routingkey %.*s\n",
|
||||
(unsigned)envelope.delivery_tag, (int)envelope.exchange.len,
|
||||
(char *)envelope.exchange.bytes, (int)envelope.routing_key.len,
|
||||
(char *)envelope.routing_key.bytes);
|
||||
|
||||
if (envelope.message.properties._flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
|
||||
printf("Content-type: %.*s\n",
|
||||
(int)envelope.message.properties.content_type.len,
|
||||
(char *)envelope.message.properties.content_type.bytes);
|
||||
}
|
||||
printf("----\n");
|
||||
|
||||
amqp_dump(envelope.message.body.bytes, envelope.message.body.len);
|
||||
|
||||
amqp_destroy_envelope(&envelope);
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
|
||||
"Closing channel");
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define SUMMARY_EVERY_US 1000000
|
||||
|
||||
static void send_batch(amqp_connection_state_t conn, char const *queue_name,
|
||||
int rate_limit, int message_count) {
|
||||
uint64_t start_time = now_microseconds();
|
||||
int i;
|
||||
int sent = 0;
|
||||
int previous_sent = 0;
|
||||
uint64_t previous_report_time = start_time;
|
||||
uint64_t next_summary_time = start_time + SUMMARY_EVERY_US;
|
||||
|
||||
char message[256];
|
||||
amqp_bytes_t message_bytes;
|
||||
|
||||
for (i = 0; i < (int)sizeof(message); i++) {
|
||||
message[i] = i & 0xff;
|
||||
}
|
||||
|
||||
message_bytes.len = sizeof(message);
|
||||
message_bytes.bytes = message;
|
||||
|
||||
for (i = 0; i < message_count; i++) {
|
||||
uint64_t now = now_microseconds();
|
||||
|
||||
die_on_error(amqp_basic_publish(conn, 1, amqp_cstring_bytes("amq.direct"),
|
||||
amqp_cstring_bytes(queue_name), 0, 0, NULL,
|
||||
message_bytes),
|
||||
"Publishing");
|
||||
sent++;
|
||||
if (now > next_summary_time) {
|
||||
int countOverInterval = sent - previous_sent;
|
||||
double intervalRate =
|
||||
countOverInterval / ((now - previous_report_time) / 1000000.0);
|
||||
printf("%d ms: Sent %d - %d since last report (%d Hz)\n",
|
||||
(int)(now - start_time) / 1000, sent, countOverInterval,
|
||||
(int)intervalRate);
|
||||
|
||||
previous_sent = sent;
|
||||
previous_report_time = now;
|
||||
next_summary_time += SUMMARY_EVERY_US;
|
||||
}
|
||||
|
||||
while (((i * 1000000.0) / (now - start_time)) > rate_limit) {
|
||||
microsleep(2000);
|
||||
now = now_microseconds();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint64_t stop_time = now_microseconds();
|
||||
int total_delta = (int)(stop_time - start_time);
|
||||
|
||||
printf("PRODUCER - Message count: %d\n", message_count);
|
||||
printf("Total time, milliseconds: %d\n", total_delta / 1000);
|
||||
printf("Overall messages-per-second: %g\n",
|
||||
(message_count / (total_delta / 1000000.0)));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char const *const *argv) {
|
||||
char const *hostname;
|
||||
int port, status;
|
||||
int rate_limit;
|
||||
int message_count;
|
||||
amqp_socket_t *socket = NULL;
|
||||
amqp_connection_state_t conn;
|
||||
|
||||
if (argc < 5) {
|
||||
fprintf(stderr,
|
||||
"Usage: amqp_producer host port rate_limit message_count\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
rate_limit = atoi(argv[3]);
|
||||
message_count = atoi(argv[4]);
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating TCP socket");
|
||||
}
|
||||
|
||||
status = amqp_socket_open(socket, hostname, port);
|
||||
if (status) {
|
||||
die("opening TCP socket");
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
amqp_channel_open(conn, 1);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
|
||||
|
||||
send_batch(conn, "test queue", rate_limit, message_count);
|
||||
|
||||
die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
|
||||
"Closing channel");
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
return 0;
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char const *hostname;
|
||||
int port, status;
|
||||
char const *exchange;
|
||||
char const *routingkey;
|
||||
char const *messagebody;
|
||||
amqp_socket_t *socket = NULL;
|
||||
amqp_connection_state_t conn;
|
||||
amqp_bytes_t reply_to_queue;
|
||||
|
||||
if (argc < 6) { /* minimum number of mandatory arguments */
|
||||
fprintf(stderr,
|
||||
"usage:\namqp_rpc_sendstring_client host port exchange routingkey "
|
||||
"messagebody\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
exchange = argv[3];
|
||||
routingkey = argv[4];
|
||||
messagebody = argv[5];
|
||||
|
||||
/*
|
||||
establish a channel that is used to connect RabbitMQ server
|
||||
*/
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating TCP socket");
|
||||
}
|
||||
|
||||
status = amqp_socket_open(socket, hostname, port);
|
||||
if (status) {
|
||||
die("opening TCP socket");
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
amqp_channel_open(conn, 1);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
|
||||
|
||||
/*
|
||||
create private reply_to queue
|
||||
*/
|
||||
|
||||
{
|
||||
amqp_queue_declare_ok_t *r = amqp_queue_declare(
|
||||
conn, 1, amqp_empty_bytes, 0, 0, 0, 1, amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Declaring queue");
|
||||
reply_to_queue = amqp_bytes_malloc_dup(r->queue);
|
||||
if (reply_to_queue.bytes == NULL) {
|
||||
fprintf(stderr, "Out of memory while copying queue name");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
send the message
|
||||
*/
|
||||
|
||||
{
|
||||
/*
|
||||
set properties
|
||||
*/
|
||||
amqp_basic_properties_t props;
|
||||
props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
|
||||
AMQP_BASIC_DELIVERY_MODE_FLAG | AMQP_BASIC_REPLY_TO_FLAG |
|
||||
AMQP_BASIC_CORRELATION_ID_FLAG;
|
||||
props.content_type = amqp_cstring_bytes("text/plain");
|
||||
props.delivery_mode = 2; /* persistent delivery mode */
|
||||
props.reply_to = amqp_bytes_malloc_dup(reply_to_queue);
|
||||
if (props.reply_to.bytes == NULL) {
|
||||
fprintf(stderr, "Out of memory while copying queue name");
|
||||
return 1;
|
||||
}
|
||||
props.correlation_id = amqp_cstring_bytes("1");
|
||||
|
||||
/*
|
||||
publish
|
||||
*/
|
||||
die_on_error(amqp_basic_publish(conn, 1, amqp_cstring_bytes(exchange),
|
||||
amqp_cstring_bytes(routingkey), 0, 0,
|
||||
&props, amqp_cstring_bytes(messagebody)),
|
||||
"Publishing");
|
||||
|
||||
amqp_bytes_free(props.reply_to);
|
||||
}
|
||||
|
||||
/*
|
||||
wait an answer
|
||||
*/
|
||||
|
||||
{
|
||||
amqp_basic_consume(conn, 1, reply_to_queue, amqp_empty_bytes, 0, 1, 0,
|
||||
amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming");
|
||||
amqp_bytes_free(reply_to_queue);
|
||||
|
||||
{
|
||||
amqp_frame_t frame;
|
||||
int result;
|
||||
|
||||
amqp_basic_deliver_t *d;
|
||||
amqp_basic_properties_t *p;
|
||||
size_t body_target;
|
||||
size_t body_received;
|
||||
|
||||
for (;;) {
|
||||
amqp_maybe_release_buffers(conn);
|
||||
result = amqp_simple_wait_frame(conn, &frame);
|
||||
printf("Result: %d\n", result);
|
||||
if (result < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Frame type: %u channel: %u\n", frame.frame_type, frame.channel);
|
||||
if (frame.frame_type != AMQP_FRAME_METHOD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Method: %s\n", amqp_method_name(frame.payload.method.id));
|
||||
if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
d = (amqp_basic_deliver_t *)frame.payload.method.decoded;
|
||||
printf("Delivery: %u exchange: %.*s routingkey: %.*s\n",
|
||||
(unsigned)d->delivery_tag, (int)d->exchange.len,
|
||||
(char *)d->exchange.bytes, (int)d->routing_key.len,
|
||||
(char *)d->routing_key.bytes);
|
||||
|
||||
result = amqp_simple_wait_frame(conn, &frame);
|
||||
if (result < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (frame.frame_type != AMQP_FRAME_HEADER) {
|
||||
fprintf(stderr, "Expected header!");
|
||||
abort();
|
||||
}
|
||||
p = (amqp_basic_properties_t *)frame.payload.properties.decoded;
|
||||
if (p->_flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
|
||||
printf("Content-type: %.*s\n", (int)p->content_type.len,
|
||||
(char *)p->content_type.bytes);
|
||||
}
|
||||
printf("----\n");
|
||||
|
||||
body_target = (size_t)frame.payload.properties.body_size;
|
||||
body_received = 0;
|
||||
|
||||
while (body_received < body_target) {
|
||||
result = amqp_simple_wait_frame(conn, &frame);
|
||||
if (result < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (frame.frame_type != AMQP_FRAME_BODY) {
|
||||
fprintf(stderr, "Expected body!");
|
||||
abort();
|
||||
}
|
||||
|
||||
body_received += frame.payload.body_fragment.len;
|
||||
assert(body_received <= body_target);
|
||||
|
||||
amqp_dump(frame.payload.body_fragment.bytes,
|
||||
frame.payload.body_fragment.len);
|
||||
}
|
||||
|
||||
if (body_received != body_target) {
|
||||
/* Can only happen when amqp_simple_wait_frame returns <= 0 */
|
||||
/* We break here to close the connection */
|
||||
break;
|
||||
}
|
||||
|
||||
/* everything was fine, we can quit now because we received the reply */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
closing
|
||||
*/
|
||||
|
||||
die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
|
||||
"Closing channel");
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
int main(int argc, char const *const *argv) {
|
||||
char const *hostname;
|
||||
int port, status;
|
||||
char const *exchange;
|
||||
char const *routingkey;
|
||||
char const *messagebody;
|
||||
amqp_socket_t *socket = NULL;
|
||||
amqp_connection_state_t conn;
|
||||
|
||||
if (argc < 6) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Usage: amqp_sendstring host port exchange routingkey messagebody\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
exchange = argv[3];
|
||||
routingkey = argv[4];
|
||||
messagebody = argv[5];
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating TCP socket");
|
||||
}
|
||||
|
||||
status = amqp_socket_open(socket, hostname, port);
|
||||
if (status) {
|
||||
die("opening TCP socket");
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
amqp_channel_open(conn, 1);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
|
||||
|
||||
{
|
||||
amqp_basic_properties_t props;
|
||||
props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG;
|
||||
props.content_type = amqp_cstring_bytes("text/plain");
|
||||
props.delivery_mode = 2; /* persistent delivery mode */
|
||||
die_on_error(amqp_basic_publish(conn, 1, amqp_cstring_bytes(exchange),
|
||||
amqp_cstring_bytes(routingkey), 0, 0,
|
||||
&props, amqp_cstring_bytes(messagebody)),
|
||||
"Publishing");
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
|
||||
"Closing channel");
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
return 0;
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by Mike Steinert are Copyright (c) 2012-2013
|
||||
* Mike Steinert. All Rights Reserved.
|
||||
*
|
||||
* Portions created by Bogdan Padalko are Copyright (c) 2013.
|
||||
* Bogdan Padalko. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_ssl_socket.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Winsock2.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
int main(int argc, char const *const *argv) {
|
||||
char const *hostname;
|
||||
int port;
|
||||
int timeout;
|
||||
amqp_socket_t *socket;
|
||||
amqp_connection_state_t conn;
|
||||
struct timeval tval;
|
||||
struct timeval *tv;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr,
|
||||
"Usage: amqps_connect_timeout host port timeout_sec "
|
||||
"[cacert.pem [verifypeer] [verifyhostname] [key.pem cert.pem]]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
|
||||
timeout = atoi(argv[3]);
|
||||
if (timeout > 0) {
|
||||
tv = &tval;
|
||||
|
||||
tv->tv_sec = timeout;
|
||||
tv->tv_usec = 0;
|
||||
} else {
|
||||
tv = NULL;
|
||||
}
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_ssl_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating SSL/TLS socket");
|
||||
}
|
||||
|
||||
amqp_ssl_socket_set_verify_peer(socket, 0);
|
||||
amqp_ssl_socket_set_verify_hostname(socket, 0);
|
||||
|
||||
if (argc > 5) {
|
||||
int nextarg = 5;
|
||||
die_on_error(amqp_ssl_socket_set_cacert(socket, argv[4]),
|
||||
"setting CA certificate");
|
||||
if (argc > nextarg && !strcmp("verifypeer", argv[nextarg])) {
|
||||
amqp_ssl_socket_set_verify_peer(socket, 1);
|
||||
nextarg++;
|
||||
}
|
||||
if (argc > nextarg && !strcmp("verifyhostname", argv[nextarg])) {
|
||||
amqp_ssl_socket_set_verify_hostname(socket, 1);
|
||||
nextarg++;
|
||||
}
|
||||
if (argc > nextarg + 1) {
|
||||
die_on_error(
|
||||
amqp_ssl_socket_set_key(socket, argv[nextarg + 1], argv[nextarg]),
|
||||
"setting client key");
|
||||
}
|
||||
}
|
||||
|
||||
die_on_error(amqp_socket_open_noblock(socket, hostname, port, tv),
|
||||
"opening SSL/TLS connection");
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
die_on_error(amqp_uninitialize_ssl_library(), "Uninitializing SSL library");
|
||||
|
||||
printf("Done\n");
|
||||
return 0;
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_tcp_socket.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
int main(int argc, char const *const *argv) {
|
||||
char const *hostname;
|
||||
int port, status;
|
||||
char const *exchange;
|
||||
char const *bindingkey;
|
||||
char const *queue;
|
||||
amqp_socket_t *socket = NULL;
|
||||
amqp_connection_state_t conn;
|
||||
|
||||
if (argc < 6) {
|
||||
fprintf(stderr, "Usage: amqp_unbind host port exchange bindingkey queue\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostname = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
exchange = argv[3];
|
||||
bindingkey = argv[4];
|
||||
queue = argv[5];
|
||||
|
||||
conn = amqp_new_connection();
|
||||
|
||||
socket = amqp_tcp_socket_new(conn);
|
||||
if (!socket) {
|
||||
die("creating TCP socket");
|
||||
}
|
||||
|
||||
status = amqp_socket_open(socket, hostname, port);
|
||||
if (status) {
|
||||
die("opening TCP socket");
|
||||
}
|
||||
|
||||
die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
|
||||
"guest", "guest"),
|
||||
"Logging in");
|
||||
amqp_channel_open(conn, 1);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel");
|
||||
|
||||
amqp_queue_unbind(conn, 1, amqp_cstring_bytes(queue),
|
||||
amqp_cstring_bytes(exchange),
|
||||
amqp_cstring_bytes(bindingkey), amqp_empty_table);
|
||||
die_on_amqp_error(amqp_get_rpc_reply(conn), "Unbinding");
|
||||
|
||||
die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
|
||||
"Closing channel");
|
||||
die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
|
||||
"Closing connection");
|
||||
die_on_error(amqp_destroy_connection(conn), "Ending connection");
|
||||
return 0;
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
uint64_t now_microseconds(void) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
|
||||
}
|
||||
|
||||
void microsleep(int usec) {
|
||||
struct timespec req;
|
||||
req.tv_sec = 0;
|
||||
req.tv_nsec = 1000 * usec;
|
||||
nanosleep(&req, NULL);
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <amqp.h>
|
||||
#include <amqp_framing.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
void die(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void die_on_error(int x, char const *context) {
|
||||
if (x < 0) {
|
||||
fprintf(stderr, "%s: %s\n", context, amqp_error_string2(x));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void die_on_amqp_error(amqp_rpc_reply_t x, char const *context) {
|
||||
switch (x.reply_type) {
|
||||
case AMQP_RESPONSE_NORMAL:
|
||||
return;
|
||||
|
||||
case AMQP_RESPONSE_NONE:
|
||||
fprintf(stderr, "%s: missing RPC reply type!\n", context);
|
||||
break;
|
||||
|
||||
case AMQP_RESPONSE_LIBRARY_EXCEPTION:
|
||||
fprintf(stderr, "%s: %s\n", context, amqp_error_string2(x.library_error));
|
||||
break;
|
||||
|
||||
case AMQP_RESPONSE_SERVER_EXCEPTION:
|
||||
switch (x.reply.id) {
|
||||
case AMQP_CONNECTION_CLOSE_METHOD: {
|
||||
amqp_connection_close_t *m =
|
||||
(amqp_connection_close_t *)x.reply.decoded;
|
||||
fprintf(stderr, "%s: server connection error %uh, message: %.*s\n",
|
||||
context, m->reply_code, (int)m->reply_text.len,
|
||||
(char *)m->reply_text.bytes);
|
||||
break;
|
||||
}
|
||||
case AMQP_CHANNEL_CLOSE_METHOD: {
|
||||
amqp_channel_close_t *m = (amqp_channel_close_t *)x.reply.decoded;
|
||||
fprintf(stderr, "%s: server channel error %uh, message: %.*s\n",
|
||||
context, m->reply_code, (int)m->reply_text.len,
|
||||
(char *)m->reply_text.bytes);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "%s: unknown server error, method id 0x%08X\n",
|
||||
context, x.reply.id);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void dump_row(long count, int numinrow, int *chs) {
|
||||
int i;
|
||||
|
||||
printf("%08lX:", count - numinrow);
|
||||
|
||||
if (numinrow > 0) {
|
||||
for (i = 0; i < numinrow; i++) {
|
||||
if (i == 8) {
|
||||
printf(" :");
|
||||
}
|
||||
printf(" %02X", chs[i]);
|
||||
}
|
||||
for (i = numinrow; i < 16; i++) {
|
||||
if (i == 8) {
|
||||
printf(" :");
|
||||
}
|
||||
printf(" ");
|
||||
}
|
||||
printf(" ");
|
||||
for (i = 0; i < numinrow; i++) {
|
||||
if (isprint(chs[i])) {
|
||||
printf("%c", chs[i]);
|
||||
} else {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int rows_eq(int *a, int *b) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (a[i] != b[i]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void amqp_dump(void const *buffer, size_t len) {
|
||||
unsigned char *buf = (unsigned char *)buffer;
|
||||
long count = 0;
|
||||
int numinrow = 0;
|
||||
int chs[16];
|
||||
int oldchs[16] = {0};
|
||||
int showed_dots = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int ch = buf[i];
|
||||
|
||||
if (numinrow == 16) {
|
||||
int j;
|
||||
|
||||
if (rows_eq(oldchs, chs)) {
|
||||
if (!showed_dots) {
|
||||
showed_dots = 1;
|
||||
printf(
|
||||
" .. .. .. .. .. .. .. .. : .. .. .. .. .. .. .. ..\n");
|
||||
}
|
||||
} else {
|
||||
showed_dots = 0;
|
||||
dump_row(count, numinrow, chs);
|
||||
}
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
oldchs[j] = chs[j];
|
||||
}
|
||||
|
||||
numinrow = 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
chs[numinrow++] = ch;
|
||||
}
|
||||
|
||||
dump_row(count, numinrow, chs);
|
||||
|
||||
if (numinrow != 0) {
|
||||
printf("%08lX:\n", count);
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
#ifndef librabbitmq_examples_utils_h
|
||||
#define librabbitmq_examples_utils_h
|
||||
|
||||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
void die(const char *fmt, ...);
|
||||
extern void die_on_error(int x, char const *context);
|
||||
extern void die_on_amqp_error(amqp_rpc_reply_t x, char const *context);
|
||||
|
||||
extern void amqp_dump(void const *buffer, size_t len);
|
||||
|
||||
extern uint64_t now_microseconds(void);
|
||||
extern void microsleep(int usec);
|
||||
|
||||
#endif
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
uint64_t now_microseconds(void) {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
return (((uint64_t)ft.dwHighDateTime << 32) | (uint64_t)ft.dwLowDateTime) /
|
||||
10;
|
||||
}
|
||||
|
||||
void microsleep(int usec) { Sleep(usec / 1000); }
|
|
@ -1,13 +0,0 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: rabbitmq-c
|
||||
Description: An AMQP 0-9-1 client library
|
||||
Version: @VERSION@
|
||||
URL: https://github.com/alanxz/rabbitmq-c
|
||||
Requires.private: @requires_private@
|
||||
Libs: -L${libdir} -lrabbitmq
|
||||
Libs.private: @libs_private@
|
||||
CFlags: -I${includedir}
|
|
@ -1,186 +0,0 @@
|
|||
project(librabbitmq "C")
|
||||
|
||||
if (REGENERATE_AMQP_FRAMING)
|
||||
set(AMQP_CODEGEN_PY "${CMAKE_CURRENT_BINARY_DIR}/amqp_codegen.py")
|
||||
set(CODEGEN_PY "${CMAKE_CURRENT_BINARY_DIR}/codegen.py")
|
||||
set(AMQP_SPEC_JSON_PATH "${AMQP_CODEGEN_DIR}/amqp-rabbitmq-0.9.1.json")
|
||||
set(AMQP_FRAMING_H_PATH ${CMAKE_CURRENT_BINARY_DIR}/amqp_framing.h)
|
||||
set(AMQP_FRAMING_C_PATH ${CMAKE_CURRENT_BINARY_DIR}/amqp_framing.c)
|
||||
|
||||
if (PYTHON_VERSION_MAJOR GREATER 2)
|
||||
set(CONVERT_CODEGEN ${PYTHON_2TO3_EXECUTABLE} -w ${CODEGEN_PY} > codegen_2to3.out)
|
||||
set(CONVERT_AMQP_CODEGEN ${PYTHON_2TO3_EXECUTABLE} -w ${AMQP_CODEGEN_PY} > amqp_codegen_2to3.out)
|
||||
else ()
|
||||
set(CONVERT_CODEGEN "")
|
||||
set(CONVERT_AMQP_CODEGEN "")
|
||||
endif ()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CODEGEN_PY}
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/codegen.py ${CODEGEN_PY}
|
||||
COMMAND ${CONVERT_CODEGEN}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/codegen.py
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${AMQP_CODEGEN_PY}
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy ${AMQP_CODEGEN_DIR}/amqp_codegen.py ${AMQP_CODEGEN_PY}
|
||||
COMMAND ${CONVERT_AMQP_CODEGEN}
|
||||
DEPENDS ${AMQP_CODEGEN_DIR}/amqp_codegen.py ${AMQP_CODEGEN_TARGET}
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${AMQP_FRAMING_H_PATH}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ARGS ${CODEGEN_PY} header ${AMQP_SPEC_JSON_PATH} ${AMQP_FRAMING_H_PATH}
|
||||
DEPENDS ${AMQP_SPEC_JSON_PATH} ${CODEGEN_PY} ${AMQP_CODEGEN_PY}
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${AMQP_FRAMING_C_PATH}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ARGS ${CODEGEN_PY} body ${AMQP_SPEC_JSON_PATH} ${AMQP_FRAMING_C_PATH}
|
||||
DEPENDS ${AMQP_SPEC_JSON_PATH} ${CODEGEN_PY} ${AMQP_CODEGEN_PY}
|
||||
VERBATIM)
|
||||
else (REGENERATE_AMQP_FRAMING)
|
||||
set(AMQP_FRAMING_H_PATH ${CMAKE_CURRENT_SOURCE_DIR}/amqp_framing.h)
|
||||
set(AMQP_FRAMING_C_PATH ${CMAKE_CURRENT_SOURCE_DIR}/amqp_framing.c)
|
||||
endif (REGENERATE_AMQP_FRAMING)
|
||||
|
||||
if(WIN32)
|
||||
set(SOCKET_IMPL "win32")
|
||||
else(WIN32)
|
||||
set(SOCKET_IMPL "unix")
|
||||
endif(WIN32)
|
||||
|
||||
if(MSVC)
|
||||
if(MSVC_VERSION LESS 1600)
|
||||
set(MSINTTYPES_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/win32/msinttypes")
|
||||
set(STDINT_H_INSTALL_FILE "${CMAKE_CURRENT_SOURCE_DIR}/win32/msinttypes/stdint.h")
|
||||
endif(MSVC_VERSION LESS 1600)
|
||||
endif(MSVC)
|
||||
|
||||
# NOTE: order is important here: if we generate amqp_framing.h/.c it'll be in the
|
||||
# binary directory, and should shadow whats in the source directory
|
||||
set(LIBRABBITMQ_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${SOCKET_IMPL}
|
||||
${MSINTTYPES_INCLUDE}
|
||||
)
|
||||
|
||||
include_directories(${LIBRABBITMQ_INCLUDE_DIRS})
|
||||
|
||||
set(LIBRABBITMQ_INCLUDE_DIRS
|
||||
${LIBRABBITMQ_INCLUDE_DIRS}
|
||||
PARENT_SCOPE)
|
||||
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
|
||||
if (ENABLE_SSL_SUPPORT)
|
||||
add_definitions(-DWITH_SSL=1)
|
||||
set(AMQP_SSL_SOCKET_H_PATH amqp_ssl_socket.h)
|
||||
|
||||
set(AMQP_SSL_SRCS ${AMQP_SSL_SOCKET_H_PATH}
|
||||
amqp_openssl.c
|
||||
amqp_openssl_hostname_validation.c
|
||||
amqp_openssl_hostname_validation.h
|
||||
amqp_hostcheck.c
|
||||
amqp_hostcheck.h
|
||||
amqp_openssl_bio.c
|
||||
amqp_openssl_bio.h
|
||||
)
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
set(AMQP_SSL_LIBS ${OPENSSL_LIBRARIES})
|
||||
if (APPLE)
|
||||
# Apple has deprecated OpenSSL in 10.7+. This disables that warning.
|
||||
set_source_files_properties(${AMQP_SSL_SRCS}
|
||||
PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(AMQP_SSL_SRCS ${AMQP_SSL_SRCS} win32/threads.h win32/threads.c)
|
||||
else()
|
||||
set(AMQP_SSL_SRCS ${AMQP_SSL_SRCS} unix/threads.h)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(RABBITMQ_SOURCES
|
||||
${AMQP_FRAMING_H_PATH}
|
||||
${AMQP_FRAMING_C_PATH}
|
||||
amqp_api.c amqp.h amqp_connection.c amqp_mem.c amqp_private.h amqp_socket.c
|
||||
amqp_table.c amqp_url.c amqp_socket.h amqp_tcp_socket.c amqp_tcp_socket.h
|
||||
amqp_time.c amqp_time.h
|
||||
amqp_consumer.c
|
||||
${AMQP_SSL_SRCS}
|
||||
)
|
||||
|
||||
add_definitions(-DAMQP_BUILD)
|
||||
|
||||
set(RMQ_LIBRARIES ${AMQP_SSL_LIBS} ${SOCKET_LIBRARIES} ${LIBRT} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_library(rabbitmq SHARED ${RABBITMQ_SOURCES})
|
||||
if (THREADS_HAVE_PTHREAD_ARG)
|
||||
target_compile_options(rabbitmq PUBLIC "-pthread")
|
||||
endif()
|
||||
|
||||
target_link_libraries(rabbitmq ${RMQ_LIBRARIES})
|
||||
|
||||
if (WIN32)
|
||||
set_target_properties(rabbitmq PROPERTIES VERSION ${RMQ_VERSION} OUTPUT_NAME rabbitmq.${RMQ_SOVERSION})
|
||||
else (WIN32)
|
||||
set_target_properties(rabbitmq PROPERTIES VERSION ${RMQ_VERSION} SOVERSION ${RMQ_SOVERSION})
|
||||
endif (WIN32)
|
||||
|
||||
install(TARGETS rabbitmq
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
set(RMQ_LIBRARY_TARGET rabbitmq)
|
||||
endif (BUILD_SHARED_LIBS)
|
||||
|
||||
if (BUILD_STATIC_LIBS)
|
||||
add_library(rabbitmq-static STATIC ${RABBITMQ_SOURCES})
|
||||
if (THREADS_HAVE_PTHREAD_ARG)
|
||||
target_compile_options(rabbitmq-static PUBLIC "-pthread")
|
||||
endif()
|
||||
|
||||
target_link_libraries(rabbitmq-static ${RMQ_LIBRARIES})
|
||||
|
||||
set_target_properties(rabbitmq-static PROPERTIES COMPILE_DEFINITIONS AMQP_STATIC)
|
||||
if (WIN32)
|
||||
set_target_properties(rabbitmq-static PROPERTIES
|
||||
VERSION ${RMQ_VERSION}
|
||||
OUTPUT_NAME librabbitmq.${RMQ_SOVERSION})
|
||||
|
||||
if(MSVC)
|
||||
set_target_properties(rabbitmq-static PROPERTIES
|
||||
# Embed debugging info in the library itself instead of generating
|
||||
# a .pdb file.
|
||||
COMPILE_OPTIONS "/Z7")
|
||||
endif(MSVC)
|
||||
|
||||
else (WIN32)
|
||||
set_target_properties(rabbitmq-static PROPERTIES VERSION ${RMQ_VERSION} SOVERSION ${RMQ_SOVERSION} OUTPUT_NAME rabbitmq)
|
||||
endif (WIN32)
|
||||
|
||||
install(TARGETS rabbitmq-static
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
if (NOT DEFINED RMQ_LIBRARY_TARGET)
|
||||
set(RMQ_LIBRARY_TARGET rabbitmq-static)
|
||||
endif ()
|
||||
endif (BUILD_STATIC_LIBS)
|
||||
|
||||
install(FILES
|
||||
amqp.h
|
||||
${AMQP_FRAMING_H_PATH}
|
||||
amqp_tcp_socket.h
|
||||
${AMQP_SSL_SOCKET_H_PATH}
|
||||
${STDINT_H_INSTALL_FILE}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
)
|
||||
|
||||
set(RMQ_LIBRARY_TARGET ${RMQ_LIBRARY_TARGET} PARENT_SCOPE)
|
File diff suppressed because it is too large
Load diff
|
@ -1,394 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* MSVC complains about sprintf being deprecated in favor of sprintf_s */
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
/* MSVC complains about strdup being deprecated in favor of _strdup */
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#endif
|
||||
|
||||
#include "amqp_private.h"
|
||||
#include "amqp_time.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ERROR_MASK (0x00FF)
|
||||
#define ERROR_CATEGORY_MASK (0xFF00)
|
||||
|
||||
enum error_category_enum_ { EC_base = 0, EC_tcp = 1, EC_ssl = 2 };
|
||||
|
||||
static const char *base_error_strings[] = {
|
||||
/* AMQP_STATUS_OK 0x0 */
|
||||
"operation completed successfully",
|
||||
/* AMQP_STATUS_NO_MEMORY -0x0001 */
|
||||
"could not allocate memory",
|
||||
/* AMQP_STATUS_BAD_AQMP_DATA -0x0002 */
|
||||
"invalid AMQP data",
|
||||
/* AMQP_STATUS_UNKNOWN_CLASS -0x0003 */
|
||||
"unknown AMQP class id",
|
||||
/* AMQP_STATUS_UNKNOWN_METHOD -0x0004 */
|
||||
"unknown AMQP method id",
|
||||
/* AMQP_STATUS_HOSTNAME_RESOLUTION_FAILED -0x0005 */
|
||||
"hostname lookup failed",
|
||||
/* AMQP_STATUS_INCOMPATIBLE_AMQP_VERSION -0x0006 */
|
||||
"incompatible AMQP version",
|
||||
/* AMQP_STATUS_CONNECTION_CLOSED -0x0007 */
|
||||
"connection closed unexpectedly",
|
||||
/* AMQP_STATUS_BAD_AMQP_URL -0x0008 */
|
||||
"could not parse AMQP URL",
|
||||
/* AMQP_STATUS_SOCKET_ERROR -0x0009 */
|
||||
"a socket error occurred",
|
||||
/* AMQP_STATUS_INVALID_PARAMETER -0x000A */
|
||||
"invalid parameter",
|
||||
/* AMQP_STATUS_TABLE_TOO_BIG -0x000B */
|
||||
"table too large for buffer",
|
||||
/* AMQP_STATUS_WRONG_METHOD -0x000C */
|
||||
"unexpected method received",
|
||||
/* AMQP_STATUS_TIMEOUT -0x000D */
|
||||
"request timed out",
|
||||
/* AMQP_STATUS_TIMER_FAILED -0x000E */
|
||||
"system timer has failed",
|
||||
/* AMQP_STATUS_HEARTBEAT_TIMEOUT -0x000F */
|
||||
"heartbeat timeout, connection closed",
|
||||
/* AMQP_STATUS_UNEXPECTED STATE -0x0010 */
|
||||
"unexpected protocol state",
|
||||
/* AMQP_STATUS_SOCKET_CLOSED -0x0011 */
|
||||
"socket is closed",
|
||||
/* AMQP_STATUS_SOCKET_INUSE -0x0012 */
|
||||
"socket already open",
|
||||
/* AMQP_STATUS_BROKER_UNSUPPORTED_SASL_METHOD -0x00013 */
|
||||
"unsupported sasl method requested",
|
||||
/* AMQP_STATUS_UNSUPPORTED -0x0014 */
|
||||
"parameter value is unsupported"};
|
||||
|
||||
static const char *tcp_error_strings[] = {
|
||||
/* AMQP_STATUS_TCP_ERROR -0x0100 */
|
||||
"a socket error occurred",
|
||||
/* AMQP_STATUS_TCP_SOCKETLIB_INIT_ERROR -0x0101 */
|
||||
"socket library initialization failed"};
|
||||
|
||||
static const char *ssl_error_strings[] = {
|
||||
/* AMQP_STATUS_SSL_ERRO R -0x0200 */
|
||||
"a SSL error occurred",
|
||||
/* AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED -0x0201 */
|
||||
"SSL hostname verification failed",
|
||||
/* AMQP_STATUS_SSL_PEER_VERIFY_FAILED -0x0202 */
|
||||
"SSL peer cert verification failed",
|
||||
/* AMQP_STATUS_SSL_CONNECTION_FAILED -0x0203 */
|
||||
"SSL handshake failed"};
|
||||
|
||||
static const char *unknown_error_string = "(unknown error)";
|
||||
|
||||
const char *amqp_error_string2(int code) {
|
||||
const char *error_string;
|
||||
size_t category = (((-code) & ERROR_CATEGORY_MASK) >> 8);
|
||||
size_t error = (-code) & ERROR_MASK;
|
||||
|
||||
switch (category) {
|
||||
case EC_base:
|
||||
if (error < (sizeof(base_error_strings) / sizeof(char *))) {
|
||||
error_string = base_error_strings[error];
|
||||
} else {
|
||||
error_string = unknown_error_string;
|
||||
}
|
||||
break;
|
||||
|
||||
case EC_tcp:
|
||||
if (error < (sizeof(tcp_error_strings) / sizeof(char *))) {
|
||||
error_string = tcp_error_strings[error];
|
||||
} else {
|
||||
error_string = unknown_error_string;
|
||||
}
|
||||
break;
|
||||
|
||||
case EC_ssl:
|
||||
if (error < (sizeof(ssl_error_strings) / sizeof(char *))) {
|
||||
error_string = ssl_error_strings[error];
|
||||
} else {
|
||||
error_string = unknown_error_string;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
error_string = unknown_error_string;
|
||||
break;
|
||||
}
|
||||
|
||||
return error_string;
|
||||
}
|
||||
|
||||
char *amqp_error_string(int code) {
|
||||
/* Previously sometimes clients had to flip the sign on a return value from a
|
||||
* function to get the correct error code. Now, all error codes are negative.
|
||||
* To keep people's legacy code running correctly, we map all error codes to
|
||||
* negative values.
|
||||
*
|
||||
* This is only done with this deprecated function.
|
||||
*/
|
||||
if (code > 0) {
|
||||
code = -code;
|
||||
}
|
||||
return strdup(amqp_error_string2(code));
|
||||
}
|
||||
|
||||
void amqp_abort(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
const amqp_bytes_t amqp_empty_bytes = {0, NULL};
|
||||
const amqp_table_t amqp_empty_table = {0, NULL};
|
||||
const amqp_array_t amqp_empty_array = {0, NULL};
|
||||
|
||||
int amqp_basic_publish(amqp_connection_state_t state, amqp_channel_t channel,
|
||||
amqp_bytes_t exchange, amqp_bytes_t routing_key,
|
||||
amqp_boolean_t mandatory, amqp_boolean_t immediate,
|
||||
amqp_basic_properties_t const *properties,
|
||||
amqp_bytes_t body) {
|
||||
amqp_frame_t f;
|
||||
size_t body_offset;
|
||||
size_t usable_body_payload_size =
|
||||
state->frame_max - (HEADER_SIZE + FOOTER_SIZE);
|
||||
int res;
|
||||
int flagz;
|
||||
|
||||
amqp_basic_publish_t m;
|
||||
amqp_basic_properties_t default_properties;
|
||||
|
||||
m.exchange = exchange;
|
||||
m.routing_key = routing_key;
|
||||
m.mandatory = mandatory;
|
||||
m.immediate = immediate;
|
||||
m.ticket = 0;
|
||||
|
||||
/* TODO(alanxz): this heartbeat check is happening in the wrong place, it
|
||||
* should really be done in amqp_try_send/writev */
|
||||
res = amqp_time_has_past(state->next_recv_heartbeat);
|
||||
if (AMQP_STATUS_TIMER_FAILURE == res) {
|
||||
return res;
|
||||
} else if (AMQP_STATUS_TIMEOUT == res) {
|
||||
res = amqp_try_recv(state);
|
||||
if (AMQP_STATUS_TIMEOUT == res) {
|
||||
return AMQP_STATUS_HEARTBEAT_TIMEOUT;
|
||||
} else if (AMQP_STATUS_OK != res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
res = amqp_send_method_inner(state, channel, AMQP_BASIC_PUBLISH_METHOD, &m,
|
||||
AMQP_SF_MORE, amqp_time_infinite());
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (properties == NULL) {
|
||||
memset(&default_properties, 0, sizeof(default_properties));
|
||||
properties = &default_properties;
|
||||
}
|
||||
|
||||
f.frame_type = AMQP_FRAME_HEADER;
|
||||
f.channel = channel;
|
||||
f.payload.properties.class_id = AMQP_BASIC_CLASS;
|
||||
f.payload.properties.body_size = body.len;
|
||||
f.payload.properties.decoded = (void *)properties;
|
||||
|
||||
if (body.len > 0) {
|
||||
flagz = AMQP_SF_MORE;
|
||||
} else {
|
||||
flagz = AMQP_SF_NONE;
|
||||
}
|
||||
res = amqp_send_frame_inner(state, &f, flagz, amqp_time_infinite());
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
body_offset = 0;
|
||||
while (body_offset < body.len) {
|
||||
size_t remaining = body.len - body_offset;
|
||||
|
||||
if (remaining == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
f.frame_type = AMQP_FRAME_BODY;
|
||||
f.channel = channel;
|
||||
f.payload.body_fragment.bytes = amqp_offset(body.bytes, body_offset);
|
||||
if (remaining >= usable_body_payload_size) {
|
||||
f.payload.body_fragment.len = usable_body_payload_size;
|
||||
flagz = AMQP_SF_MORE;
|
||||
} else {
|
||||
f.payload.body_fragment.len = remaining;
|
||||
flagz = AMQP_SF_NONE;
|
||||
}
|
||||
|
||||
body_offset += f.payload.body_fragment.len;
|
||||
res = amqp_send_frame_inner(state, &f, flagz, amqp_time_infinite());
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
amqp_rpc_reply_t amqp_channel_close(amqp_connection_state_t state,
|
||||
amqp_channel_t channel, int code) {
|
||||
char codestr[13];
|
||||
amqp_method_number_t replies[2] = {AMQP_CHANNEL_CLOSE_OK_METHOD, 0};
|
||||
amqp_channel_close_t req;
|
||||
|
||||
if (code < 0 || code > UINT16_MAX) {
|
||||
return amqp_rpc_reply_error(AMQP_STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
req.reply_code = (uint16_t)code;
|
||||
req.reply_text.bytes = codestr;
|
||||
req.reply_text.len = sprintf(codestr, "%d", code);
|
||||
req.class_id = 0;
|
||||
req.method_id = 0;
|
||||
|
||||
return amqp_simple_rpc(state, channel, AMQP_CHANNEL_CLOSE_METHOD, replies,
|
||||
&req);
|
||||
}
|
||||
|
||||
amqp_rpc_reply_t amqp_connection_close(amqp_connection_state_t state,
|
||||
int code) {
|
||||
char codestr[13];
|
||||
amqp_method_number_t replies[2] = {AMQP_CONNECTION_CLOSE_OK_METHOD, 0};
|
||||
amqp_channel_close_t req;
|
||||
|
||||
if (code < 0 || code > UINT16_MAX) {
|
||||
return amqp_rpc_reply_error(AMQP_STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
req.reply_code = (uint16_t)code;
|
||||
req.reply_text.bytes = codestr;
|
||||
req.reply_text.len = sprintf(codestr, "%d", code);
|
||||
req.class_id = 0;
|
||||
req.method_id = 0;
|
||||
|
||||
return amqp_simple_rpc(state, 0, AMQP_CONNECTION_CLOSE_METHOD, replies, &req);
|
||||
}
|
||||
|
||||
int amqp_basic_ack(amqp_connection_state_t state, amqp_channel_t channel,
|
||||
uint64_t delivery_tag, amqp_boolean_t multiple) {
|
||||
amqp_basic_ack_t m;
|
||||
m.delivery_tag = delivery_tag;
|
||||
m.multiple = multiple;
|
||||
return amqp_send_method(state, channel, AMQP_BASIC_ACK_METHOD, &m);
|
||||
}
|
||||
|
||||
amqp_rpc_reply_t amqp_basic_get(amqp_connection_state_t state,
|
||||
amqp_channel_t channel, amqp_bytes_t queue,
|
||||
amqp_boolean_t no_ack) {
|
||||
amqp_method_number_t replies[] = {AMQP_BASIC_GET_OK_METHOD,
|
||||
AMQP_BASIC_GET_EMPTY_METHOD, 0};
|
||||
amqp_basic_get_t req;
|
||||
req.ticket = 0;
|
||||
req.queue = queue;
|
||||
req.no_ack = no_ack;
|
||||
|
||||
state->most_recent_api_result =
|
||||
amqp_simple_rpc(state, channel, AMQP_BASIC_GET_METHOD, replies, &req);
|
||||
return state->most_recent_api_result;
|
||||
}
|
||||
|
||||
int amqp_basic_reject(amqp_connection_state_t state, amqp_channel_t channel,
|
||||
uint64_t delivery_tag, amqp_boolean_t requeue) {
|
||||
amqp_basic_reject_t req;
|
||||
req.delivery_tag = delivery_tag;
|
||||
req.requeue = requeue;
|
||||
return amqp_send_method(state, channel, AMQP_BASIC_REJECT_METHOD, &req);
|
||||
}
|
||||
|
||||
int amqp_basic_nack(amqp_connection_state_t state, amqp_channel_t channel,
|
||||
uint64_t delivery_tag, amqp_boolean_t multiple,
|
||||
amqp_boolean_t requeue) {
|
||||
amqp_basic_nack_t req;
|
||||
req.delivery_tag = delivery_tag;
|
||||
req.multiple = multiple;
|
||||
req.requeue = requeue;
|
||||
return amqp_send_method(state, channel, AMQP_BASIC_NACK_METHOD, &req);
|
||||
}
|
||||
|
||||
struct timeval *amqp_get_handshake_timeout(amqp_connection_state_t state) {
|
||||
return state->handshake_timeout;
|
||||
}
|
||||
|
||||
int amqp_set_handshake_timeout(amqp_connection_state_t state,
|
||||
struct timeval *timeout) {
|
||||
if (timeout) {
|
||||
if (timeout->tv_sec < 0 || timeout->tv_usec < 0) {
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
state->internal_handshake_timeout = *timeout;
|
||||
state->handshake_timeout = &state->internal_handshake_timeout;
|
||||
} else {
|
||||
state->handshake_timeout = NULL;
|
||||
}
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
struct timeval *amqp_get_rpc_timeout(amqp_connection_state_t state) {
|
||||
return state->rpc_timeout;
|
||||
}
|
||||
|
||||
int amqp_set_rpc_timeout(amqp_connection_state_t state,
|
||||
struct timeval *timeout) {
|
||||
if (timeout) {
|
||||
if (timeout->tv_sec < 0 || timeout->tv_usec < 0) {
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
state->rpc_timeout = &state->internal_rpc_timeout;
|
||||
*state->rpc_timeout = *timeout;
|
||||
} else {
|
||||
state->rpc_timeout = NULL;
|
||||
}
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
|
@ -1,595 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2014
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "amqp_private.h"
|
||||
#include "amqp_tcp_socket.h"
|
||||
#include "amqp_time.h"
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef AMQP_INITIAL_FRAME_POOL_PAGE_SIZE
|
||||
#define AMQP_INITIAL_FRAME_POOL_PAGE_SIZE 65536
|
||||
#endif
|
||||
|
||||
#ifndef AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE
|
||||
#define AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE 131072
|
||||
#endif
|
||||
|
||||
#ifndef AMQP_DEFAULT_LOGIN_TIMEOUT_SEC
|
||||
#define AMQP_DEFAULT_LOGIN_TIMEOUT_SEC 12
|
||||
#endif
|
||||
|
||||
#define ENFORCE_STATE(statevec, statenum) \
|
||||
{ \
|
||||
amqp_connection_state_t _check_state = (statevec); \
|
||||
amqp_connection_state_enum _wanted_state = (statenum); \
|
||||
if (_check_state->state != _wanted_state) \
|
||||
amqp_abort( \
|
||||
"Programming error: invalid AMQP connection state: expected %d, " \
|
||||
"got %d", \
|
||||
_wanted_state, _check_state->state); \
|
||||
}
|
||||
|
||||
amqp_connection_state_t amqp_new_connection(void) {
|
||||
int res;
|
||||
amqp_connection_state_t state = (amqp_connection_state_t)calloc(
|
||||
1, sizeof(struct amqp_connection_state_t_));
|
||||
|
||||
if (state == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = amqp_tune_connection(state, 0, AMQP_INITIAL_FRAME_POOL_PAGE_SIZE, 0);
|
||||
if (0 != res) {
|
||||
goto out_nomem;
|
||||
}
|
||||
|
||||
state->inbound_buffer.bytes = state->header_buffer;
|
||||
state->inbound_buffer.len = sizeof(state->header_buffer);
|
||||
|
||||
state->state = CONNECTION_STATE_INITIAL;
|
||||
/* the server protocol version response is 8 bytes, which conveniently
|
||||
is also the minimum frame size */
|
||||
state->target_size = 8;
|
||||
|
||||
state->sock_inbound_buffer.len = AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE;
|
||||
state->sock_inbound_buffer.bytes =
|
||||
malloc(AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE);
|
||||
if (state->sock_inbound_buffer.bytes == NULL) {
|
||||
goto out_nomem;
|
||||
}
|
||||
|
||||
init_amqp_pool(&state->properties_pool, 512);
|
||||
|
||||
/* Use address of the internal_handshake_timeout object by default. */
|
||||
state->internal_handshake_timeout.tv_sec = AMQP_DEFAULT_LOGIN_TIMEOUT_SEC;
|
||||
state->internal_handshake_timeout.tv_usec = 0;
|
||||
state->handshake_timeout = &state->internal_handshake_timeout;
|
||||
|
||||
return state;
|
||||
|
||||
out_nomem:
|
||||
free(state->sock_inbound_buffer.bytes);
|
||||
free(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int amqp_get_sockfd(amqp_connection_state_t state) {
|
||||
return state->socket ? amqp_socket_get_sockfd(state->socket) : -1;
|
||||
}
|
||||
|
||||
void amqp_set_sockfd(amqp_connection_state_t state, int sockfd) {
|
||||
amqp_socket_t *socket = amqp_tcp_socket_new(state);
|
||||
if (!socket) {
|
||||
amqp_abort("%s", strerror(errno));
|
||||
}
|
||||
amqp_tcp_socket_set_sockfd(socket, sockfd);
|
||||
}
|
||||
|
||||
void amqp_set_socket(amqp_connection_state_t state, amqp_socket_t *socket) {
|
||||
amqp_socket_delete(state->socket);
|
||||
state->socket = socket;
|
||||
}
|
||||
|
||||
amqp_socket_t *amqp_get_socket(amqp_connection_state_t state) {
|
||||
return state->socket;
|
||||
}
|
||||
|
||||
int amqp_tune_connection(amqp_connection_state_t state, int channel_max,
|
||||
int frame_max, int heartbeat) {
|
||||
void *newbuf;
|
||||
int res;
|
||||
|
||||
ENFORCE_STATE(state, CONNECTION_STATE_IDLE);
|
||||
|
||||
state->channel_max = channel_max;
|
||||
state->frame_max = frame_max;
|
||||
|
||||
state->heartbeat = heartbeat;
|
||||
if (0 > state->heartbeat) {
|
||||
state->heartbeat = 0;
|
||||
}
|
||||
|
||||
res = amqp_time_s_from_now(&state->next_send_heartbeat,
|
||||
amqp_heartbeat_send(state));
|
||||
if (AMQP_STATUS_OK != res) {
|
||||
return res;
|
||||
}
|
||||
res = amqp_time_s_from_now(&state->next_recv_heartbeat,
|
||||
amqp_heartbeat_recv(state));
|
||||
if (AMQP_STATUS_OK != res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
state->outbound_buffer.len = frame_max;
|
||||
newbuf = realloc(state->outbound_buffer.bytes, frame_max);
|
||||
if (newbuf == NULL) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
state->outbound_buffer.bytes = newbuf;
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
int amqp_get_channel_max(amqp_connection_state_t state) {
|
||||
return state->channel_max;
|
||||
}
|
||||
|
||||
int amqp_get_frame_max(amqp_connection_state_t state) {
|
||||
return state->frame_max;
|
||||
}
|
||||
|
||||
int amqp_get_heartbeat(amqp_connection_state_t state) {
|
||||
return state->heartbeat;
|
||||
}
|
||||
|
||||
int amqp_destroy_connection(amqp_connection_state_t state) {
|
||||
int status = AMQP_STATUS_OK;
|
||||
if (state) {
|
||||
int i;
|
||||
for (i = 0; i < POOL_TABLE_SIZE; ++i) {
|
||||
amqp_pool_table_entry_t *entry = state->pool_table[i];
|
||||
while (NULL != entry) {
|
||||
amqp_pool_table_entry_t *todelete = entry;
|
||||
empty_amqp_pool(&entry->pool);
|
||||
entry = entry->next;
|
||||
free(todelete);
|
||||
}
|
||||
}
|
||||
|
||||
free(state->outbound_buffer.bytes);
|
||||
free(state->sock_inbound_buffer.bytes);
|
||||
amqp_socket_delete(state->socket);
|
||||
empty_amqp_pool(&state->properties_pool);
|
||||
free(state);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void return_to_idle(amqp_connection_state_t state) {
|
||||
state->inbound_buffer.len = sizeof(state->header_buffer);
|
||||
state->inbound_buffer.bytes = state->header_buffer;
|
||||
state->inbound_offset = 0;
|
||||
state->target_size = HEADER_SIZE;
|
||||
state->state = CONNECTION_STATE_IDLE;
|
||||
}
|
||||
|
||||
static size_t consume_data(amqp_connection_state_t state,
|
||||
amqp_bytes_t *received_data) {
|
||||
/* how much data is available and will fit? */
|
||||
size_t bytes_consumed = state->target_size - state->inbound_offset;
|
||||
if (received_data->len < bytes_consumed) {
|
||||
bytes_consumed = received_data->len;
|
||||
}
|
||||
|
||||
memcpy(amqp_offset(state->inbound_buffer.bytes, state->inbound_offset),
|
||||
received_data->bytes, bytes_consumed);
|
||||
state->inbound_offset += bytes_consumed;
|
||||
received_data->bytes = amqp_offset(received_data->bytes, bytes_consumed);
|
||||
received_data->len -= bytes_consumed;
|
||||
|
||||
return bytes_consumed;
|
||||
}
|
||||
|
||||
int amqp_handle_input(amqp_connection_state_t state, amqp_bytes_t received_data,
|
||||
amqp_frame_t *decoded_frame) {
|
||||
size_t bytes_consumed;
|
||||
void *raw_frame;
|
||||
|
||||
/* Returning frame_type of zero indicates either insufficient input,
|
||||
or a complete, ignored frame was read. */
|
||||
decoded_frame->frame_type = 0;
|
||||
|
||||
if (received_data.len == 0) {
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
if (state->state == CONNECTION_STATE_IDLE) {
|
||||
state->state = CONNECTION_STATE_HEADER;
|
||||
}
|
||||
|
||||
bytes_consumed = consume_data(state, &received_data);
|
||||
|
||||
/* do we have target_size data yet? if not, return with the
|
||||
expectation that more will arrive */
|
||||
if (state->inbound_offset < state->target_size) {
|
||||
return (int)bytes_consumed;
|
||||
}
|
||||
|
||||
raw_frame = state->inbound_buffer.bytes;
|
||||
|
||||
switch (state->state) {
|
||||
case CONNECTION_STATE_INITIAL:
|
||||
/* check for a protocol header from the server */
|
||||
if (memcmp(raw_frame, "AMQP", 4) == 0) {
|
||||
decoded_frame->frame_type = AMQP_PSEUDOFRAME_PROTOCOL_HEADER;
|
||||
decoded_frame->channel = 0;
|
||||
|
||||
decoded_frame->payload.protocol_header.transport_high =
|
||||
amqp_d8(amqp_offset(raw_frame, 4));
|
||||
decoded_frame->payload.protocol_header.transport_low =
|
||||
amqp_d8(amqp_offset(raw_frame, 5));
|
||||
decoded_frame->payload.protocol_header.protocol_version_major =
|
||||
amqp_d8(amqp_offset(raw_frame, 6));
|
||||
decoded_frame->payload.protocol_header.protocol_version_minor =
|
||||
amqp_d8(amqp_offset(raw_frame, 7));
|
||||
|
||||
return_to_idle(state);
|
||||
return (int)bytes_consumed;
|
||||
}
|
||||
|
||||
/* it's not a protocol header; fall through to process it as a
|
||||
regular frame header */
|
||||
|
||||
case CONNECTION_STATE_HEADER: {
|
||||
amqp_channel_t channel;
|
||||
amqp_pool_t *channel_pool;
|
||||
/* frame length is 3 bytes in */
|
||||
channel = amqp_d16(amqp_offset(raw_frame, 1));
|
||||
|
||||
state->target_size =
|
||||
amqp_d32(amqp_offset(raw_frame, 3)) + HEADER_SIZE + FOOTER_SIZE;
|
||||
|
||||
if ((size_t)state->frame_max < state->target_size) {
|
||||
return AMQP_STATUS_BAD_AMQP_DATA;
|
||||
}
|
||||
|
||||
channel_pool = amqp_get_or_create_channel_pool(state, channel);
|
||||
if (NULL == channel_pool) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
amqp_pool_alloc_bytes(channel_pool, state->target_size,
|
||||
&state->inbound_buffer);
|
||||
if (NULL == state->inbound_buffer.bytes) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
memcpy(state->inbound_buffer.bytes, state->header_buffer, HEADER_SIZE);
|
||||
raw_frame = state->inbound_buffer.bytes;
|
||||
|
||||
state->state = CONNECTION_STATE_BODY;
|
||||
|
||||
bytes_consumed += consume_data(state, &received_data);
|
||||
|
||||
/* do we have target_size data yet? if not, return with the
|
||||
expectation that more will arrive */
|
||||
if (state->inbound_offset < state->target_size) {
|
||||
return (int)bytes_consumed;
|
||||
}
|
||||
}
|
||||
/* fall through to process body */
|
||||
|
||||
case CONNECTION_STATE_BODY: {
|
||||
amqp_bytes_t encoded;
|
||||
int res;
|
||||
amqp_pool_t *channel_pool;
|
||||
|
||||
/* Check frame end marker (footer) */
|
||||
if (amqp_d8(amqp_offset(raw_frame, state->target_size - 1)) !=
|
||||
AMQP_FRAME_END) {
|
||||
return AMQP_STATUS_BAD_AMQP_DATA;
|
||||
}
|
||||
|
||||
decoded_frame->frame_type = amqp_d8(amqp_offset(raw_frame, 0));
|
||||
decoded_frame->channel = amqp_d16(amqp_offset(raw_frame, 1));
|
||||
|
||||
channel_pool =
|
||||
amqp_get_or_create_channel_pool(state, decoded_frame->channel);
|
||||
if (NULL == channel_pool) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
switch (decoded_frame->frame_type) {
|
||||
case AMQP_FRAME_METHOD:
|
||||
decoded_frame->payload.method.id =
|
||||
amqp_d32(amqp_offset(raw_frame, HEADER_SIZE));
|
||||
encoded.bytes = amqp_offset(raw_frame, HEADER_SIZE + 4);
|
||||
encoded.len = state->target_size - HEADER_SIZE - 4 - FOOTER_SIZE;
|
||||
|
||||
res = amqp_decode_method(decoded_frame->payload.method.id,
|
||||
channel_pool, encoded,
|
||||
&decoded_frame->payload.method.decoded);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AMQP_FRAME_HEADER:
|
||||
decoded_frame->payload.properties.class_id =
|
||||
amqp_d16(amqp_offset(raw_frame, HEADER_SIZE));
|
||||
/* unused 2-byte weight field goes here */
|
||||
decoded_frame->payload.properties.body_size =
|
||||
amqp_d64(amqp_offset(raw_frame, HEADER_SIZE + 4));
|
||||
encoded.bytes = amqp_offset(raw_frame, HEADER_SIZE + 12);
|
||||
encoded.len = state->target_size - HEADER_SIZE - 12 - FOOTER_SIZE;
|
||||
decoded_frame->payload.properties.raw = encoded;
|
||||
|
||||
res = amqp_decode_properties(
|
||||
decoded_frame->payload.properties.class_id, channel_pool, encoded,
|
||||
&decoded_frame->payload.properties.decoded);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AMQP_FRAME_BODY:
|
||||
decoded_frame->payload.body_fragment.len =
|
||||
state->target_size - HEADER_SIZE - FOOTER_SIZE;
|
||||
decoded_frame->payload.body_fragment.bytes =
|
||||
amqp_offset(raw_frame, HEADER_SIZE);
|
||||
break;
|
||||
|
||||
case AMQP_FRAME_HEARTBEAT:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Ignore the frame */
|
||||
decoded_frame->frame_type = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return_to_idle(state);
|
||||
return (int)bytes_consumed;
|
||||
}
|
||||
|
||||
default:
|
||||
amqp_abort("Internal error: invalid amqp_connection_state_t->state %d",
|
||||
state->state);
|
||||
}
|
||||
}
|
||||
|
||||
amqp_boolean_t amqp_release_buffers_ok(amqp_connection_state_t state) {
|
||||
return (state->state == CONNECTION_STATE_IDLE);
|
||||
}
|
||||
|
||||
void amqp_release_buffers(amqp_connection_state_t state) {
|
||||
int i;
|
||||
ENFORCE_STATE(state, CONNECTION_STATE_IDLE);
|
||||
|
||||
for (i = 0; i < POOL_TABLE_SIZE; ++i) {
|
||||
amqp_pool_table_entry_t *entry = state->pool_table[i];
|
||||
|
||||
for (; NULL != entry; entry = entry->next) {
|
||||
amqp_maybe_release_buffers_on_channel(state, entry->channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void amqp_maybe_release_buffers(amqp_connection_state_t state) {
|
||||
if (amqp_release_buffers_ok(state)) {
|
||||
amqp_release_buffers(state);
|
||||
}
|
||||
}
|
||||
|
||||
void amqp_maybe_release_buffers_on_channel(amqp_connection_state_t state,
|
||||
amqp_channel_t channel) {
|
||||
amqp_link_t *queued_link;
|
||||
amqp_pool_t *pool;
|
||||
if (CONNECTION_STATE_IDLE != state->state) {
|
||||
return;
|
||||
}
|
||||
|
||||
queued_link = state->first_queued_frame;
|
||||
|
||||
while (NULL != queued_link) {
|
||||
amqp_frame_t *frame = queued_link->data;
|
||||
if (channel == frame->channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
queued_link = queued_link->next;
|
||||
}
|
||||
|
||||
pool = amqp_get_channel_pool(state, channel);
|
||||
|
||||
if (pool != NULL) {
|
||||
recycle_amqp_pool(pool);
|
||||
}
|
||||
}
|
||||
|
||||
static int amqp_frame_to_bytes(const amqp_frame_t *frame, amqp_bytes_t buffer,
|
||||
amqp_bytes_t *encoded) {
|
||||
void *out_frame = buffer.bytes;
|
||||
size_t out_frame_len;
|
||||
int res;
|
||||
|
||||
amqp_e8(frame->frame_type, amqp_offset(out_frame, 0));
|
||||
amqp_e16(frame->channel, amqp_offset(out_frame, 1));
|
||||
|
||||
switch (frame->frame_type) {
|
||||
case AMQP_FRAME_BODY: {
|
||||
const amqp_bytes_t *body = &frame->payload.body_fragment;
|
||||
|
||||
memcpy(amqp_offset(out_frame, HEADER_SIZE), body->bytes, body->len);
|
||||
|
||||
out_frame_len = body->len;
|
||||
break;
|
||||
}
|
||||
case AMQP_FRAME_METHOD: {
|
||||
amqp_bytes_t method_encoded;
|
||||
|
||||
amqp_e32(frame->payload.method.id, amqp_offset(out_frame, HEADER_SIZE));
|
||||
|
||||
method_encoded.bytes = amqp_offset(out_frame, HEADER_SIZE + 4);
|
||||
method_encoded.len = buffer.len - HEADER_SIZE - 4 - FOOTER_SIZE;
|
||||
|
||||
res = amqp_encode_method(frame->payload.method.id,
|
||||
frame->payload.method.decoded, method_encoded);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
out_frame_len = res + 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case AMQP_FRAME_HEADER: {
|
||||
amqp_bytes_t properties_encoded;
|
||||
|
||||
amqp_e16(frame->payload.properties.class_id,
|
||||
amqp_offset(out_frame, HEADER_SIZE));
|
||||
amqp_e16(0, amqp_offset(out_frame, HEADER_SIZE + 2)); /* "weight" */
|
||||
amqp_e64(frame->payload.properties.body_size,
|
||||
amqp_offset(out_frame, HEADER_SIZE + 4));
|
||||
|
||||
properties_encoded.bytes = amqp_offset(out_frame, HEADER_SIZE + 12);
|
||||
properties_encoded.len = buffer.len - HEADER_SIZE - 12 - FOOTER_SIZE;
|
||||
|
||||
res = amqp_encode_properties(frame->payload.properties.class_id,
|
||||
frame->payload.properties.decoded,
|
||||
properties_encoded);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
out_frame_len = res + 12;
|
||||
break;
|
||||
}
|
||||
|
||||
case AMQP_FRAME_HEARTBEAT:
|
||||
out_frame_len = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
amqp_e32((uint32_t)out_frame_len, amqp_offset(out_frame, 3));
|
||||
amqp_e8(AMQP_FRAME_END, amqp_offset(out_frame, HEADER_SIZE + out_frame_len));
|
||||
|
||||
encoded->bytes = out_frame;
|
||||
encoded->len = out_frame_len + HEADER_SIZE + FOOTER_SIZE;
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
int amqp_send_frame(amqp_connection_state_t state, const amqp_frame_t *frame) {
|
||||
return amqp_send_frame_inner(state, frame, AMQP_SF_NONE,
|
||||
amqp_time_infinite());
|
||||
}
|
||||
|
||||
int amqp_send_frame_inner(amqp_connection_state_t state,
|
||||
const amqp_frame_t *frame, int flags,
|
||||
amqp_time_t deadline) {
|
||||
int res;
|
||||
ssize_t sent;
|
||||
amqp_bytes_t encoded;
|
||||
amqp_time_t next_timeout;
|
||||
|
||||
/* TODO: if the AMQP_SF_MORE socket optimization can be shown to work
|
||||
* correctly, then this could be un-done so that body-frames are sent as 3
|
||||
* send calls, getting rid of the copy of the body content, some testing
|
||||
* would need to be done to see if this would actually a win for performance.
|
||||
* */
|
||||
res = amqp_frame_to_bytes(frame, state->outbound_buffer, &encoded);
|
||||
if (AMQP_STATUS_OK != res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
start_send:
|
||||
|
||||
next_timeout = amqp_time_first(deadline, state->next_recv_heartbeat);
|
||||
|
||||
sent = amqp_try_send(state, encoded.bytes, encoded.len, next_timeout, flags);
|
||||
if (0 > sent) {
|
||||
return (int)sent;
|
||||
}
|
||||
|
||||
/* A partial send has occurred, because of a heartbeat timeout (so try recv
|
||||
* something) or common timeout (so return AMQP_STATUS_TIMEOUT) */
|
||||
if ((ssize_t)encoded.len != sent) {
|
||||
if (amqp_time_equal(next_timeout, deadline)) {
|
||||
/* timeout of method was received, so return from method*/
|
||||
return AMQP_STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
res = amqp_try_recv(state);
|
||||
|
||||
if (AMQP_STATUS_TIMEOUT == res) {
|
||||
return AMQP_STATUS_HEARTBEAT_TIMEOUT;
|
||||
} else if (AMQP_STATUS_OK != res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
encoded.bytes = (uint8_t *)encoded.bytes + sent;
|
||||
encoded.len -= sent;
|
||||
goto start_send;
|
||||
}
|
||||
|
||||
res = amqp_time_s_from_now(&state->next_send_heartbeat,
|
||||
amqp_heartbeat_send(state));
|
||||
return res;
|
||||
}
|
||||
|
||||
amqp_table_t *amqp_get_server_properties(amqp_connection_state_t state) {
|
||||
return &state->server_properties;
|
||||
}
|
||||
|
||||
amqp_table_t *amqp_get_client_properties(amqp_connection_state_t state) {
|
||||
return &state->client_properties;
|
||||
}
|
|
@ -1,307 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2013-2014
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
#include "amqp.h"
|
||||
#include "amqp_private.h"
|
||||
#include "amqp_socket.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int amqp_basic_properties_clone(amqp_basic_properties_t *original,
|
||||
amqp_basic_properties_t *clone,
|
||||
amqp_pool_t *pool) {
|
||||
memset(clone, 0, sizeof(*clone));
|
||||
clone->_flags = original->_flags;
|
||||
|
||||
#define CLONE_BYTES_POOL(original, clone, pool) \
|
||||
if (0 == original.len) { \
|
||||
clone = amqp_empty_bytes; \
|
||||
} else { \
|
||||
amqp_pool_alloc_bytes(pool, original.len, &clone); \
|
||||
if (NULL == clone.bytes) { \
|
||||
return AMQP_STATUS_NO_MEMORY; \
|
||||
} \
|
||||
memcpy(clone.bytes, original.bytes, clone.len); \
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
|
||||
CLONE_BYTES_POOL(original->content_type, clone->content_type, pool)
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_CONTENT_ENCODING_FLAG) {
|
||||
CLONE_BYTES_POOL(original->content_encoding, clone->content_encoding, pool)
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_HEADERS_FLAG) {
|
||||
int res = amqp_table_clone(&original->headers, &clone->headers, pool);
|
||||
if (AMQP_STATUS_OK != res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_DELIVERY_MODE_FLAG) {
|
||||
clone->delivery_mode = original->delivery_mode;
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_PRIORITY_FLAG) {
|
||||
clone->priority = original->priority;
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_CORRELATION_ID_FLAG) {
|
||||
CLONE_BYTES_POOL(original->correlation_id, clone->correlation_id, pool)
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_REPLY_TO_FLAG) {
|
||||
CLONE_BYTES_POOL(original->reply_to, clone->reply_to, pool)
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_EXPIRATION_FLAG) {
|
||||
CLONE_BYTES_POOL(original->expiration, clone->expiration, pool)
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_MESSAGE_ID_FLAG) {
|
||||
CLONE_BYTES_POOL(original->message_id, clone->message_id, pool)
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_TIMESTAMP_FLAG) {
|
||||
clone->timestamp = original->timestamp;
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_TYPE_FLAG) {
|
||||
CLONE_BYTES_POOL(original->type, clone->type, pool)
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_USER_ID_FLAG) {
|
||||
CLONE_BYTES_POOL(original->user_id, clone->user_id, pool)
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_APP_ID_FLAG) {
|
||||
CLONE_BYTES_POOL(original->app_id, clone->app_id, pool)
|
||||
}
|
||||
|
||||
if (clone->_flags & AMQP_BASIC_CLUSTER_ID_FLAG) {
|
||||
CLONE_BYTES_POOL(original->cluster_id, clone->cluster_id, pool)
|
||||
}
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
#undef CLONE_BYTES_POOL
|
||||
}
|
||||
|
||||
void amqp_destroy_message(amqp_message_t *message) {
|
||||
empty_amqp_pool(&message->pool);
|
||||
amqp_bytes_free(message->body);
|
||||
}
|
||||
|
||||
void amqp_destroy_envelope(amqp_envelope_t *envelope) {
|
||||
amqp_destroy_message(&envelope->message);
|
||||
amqp_bytes_free(envelope->routing_key);
|
||||
amqp_bytes_free(envelope->exchange);
|
||||
amqp_bytes_free(envelope->consumer_tag);
|
||||
}
|
||||
|
||||
static int amqp_bytes_malloc_dup_failed(amqp_bytes_t bytes) {
|
||||
if (bytes.len != 0 && bytes.bytes == NULL) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
amqp_rpc_reply_t amqp_consume_message(amqp_connection_state_t state,
|
||||
amqp_envelope_t *envelope,
|
||||
struct timeval *timeout,
|
||||
AMQP_UNUSED int flags) {
|
||||
int res;
|
||||
amqp_frame_t frame;
|
||||
amqp_basic_deliver_t *delivery_method;
|
||||
amqp_rpc_reply_t ret;
|
||||
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
memset(envelope, 0, sizeof(*envelope));
|
||||
|
||||
res = amqp_simple_wait_frame_noblock(state, &frame, timeout);
|
||||
if (AMQP_STATUS_OK != res) {
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = res;
|
||||
goto error_out1;
|
||||
}
|
||||
|
||||
if (AMQP_FRAME_METHOD != frame.frame_type ||
|
||||
AMQP_BASIC_DELIVER_METHOD != frame.payload.method.id) {
|
||||
amqp_put_back_frame(state, &frame);
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = AMQP_STATUS_UNEXPECTED_STATE;
|
||||
goto error_out1;
|
||||
}
|
||||
|
||||
delivery_method = frame.payload.method.decoded;
|
||||
|
||||
envelope->channel = frame.channel;
|
||||
envelope->consumer_tag = amqp_bytes_malloc_dup(delivery_method->consumer_tag);
|
||||
envelope->delivery_tag = delivery_method->delivery_tag;
|
||||
envelope->redelivered = delivery_method->redelivered;
|
||||
envelope->exchange = amqp_bytes_malloc_dup(delivery_method->exchange);
|
||||
envelope->routing_key = amqp_bytes_malloc_dup(delivery_method->routing_key);
|
||||
|
||||
if (amqp_bytes_malloc_dup_failed(envelope->consumer_tag) ||
|
||||
amqp_bytes_malloc_dup_failed(envelope->exchange) ||
|
||||
amqp_bytes_malloc_dup_failed(envelope->routing_key)) {
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = AMQP_STATUS_NO_MEMORY;
|
||||
goto error_out2;
|
||||
}
|
||||
|
||||
ret = amqp_read_message(state, envelope->channel, &envelope->message, 0);
|
||||
if (AMQP_RESPONSE_NORMAL != ret.reply_type) {
|
||||
goto error_out2;
|
||||
}
|
||||
|
||||
ret.reply_type = AMQP_RESPONSE_NORMAL;
|
||||
return ret;
|
||||
|
||||
error_out2:
|
||||
amqp_bytes_free(envelope->routing_key);
|
||||
amqp_bytes_free(envelope->exchange);
|
||||
amqp_bytes_free(envelope->consumer_tag);
|
||||
error_out1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
amqp_rpc_reply_t amqp_read_message(amqp_connection_state_t state,
|
||||
amqp_channel_t channel,
|
||||
amqp_message_t *message,
|
||||
AMQP_UNUSED int flags) {
|
||||
amqp_frame_t frame;
|
||||
amqp_rpc_reply_t ret;
|
||||
|
||||
size_t body_read;
|
||||
char *body_read_ptr;
|
||||
int res;
|
||||
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
memset(message, 0, sizeof(*message));
|
||||
|
||||
res = amqp_simple_wait_frame_on_channel(state, channel, &frame);
|
||||
if (AMQP_STATUS_OK != res) {
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = res;
|
||||
|
||||
goto error_out1;
|
||||
}
|
||||
|
||||
if (AMQP_FRAME_HEADER != frame.frame_type) {
|
||||
if (AMQP_FRAME_METHOD == frame.frame_type &&
|
||||
(AMQP_CHANNEL_CLOSE_METHOD == frame.payload.method.id ||
|
||||
AMQP_CONNECTION_CLOSE_METHOD == frame.payload.method.id)) {
|
||||
|
||||
ret.reply_type = AMQP_RESPONSE_SERVER_EXCEPTION;
|
||||
ret.reply = frame.payload.method;
|
||||
|
||||
} else {
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = AMQP_STATUS_UNEXPECTED_STATE;
|
||||
|
||||
amqp_put_back_frame(state, &frame);
|
||||
}
|
||||
goto error_out1;
|
||||
}
|
||||
|
||||
init_amqp_pool(&message->pool, 4096);
|
||||
res = amqp_basic_properties_clone(frame.payload.properties.decoded,
|
||||
&message->properties, &message->pool);
|
||||
|
||||
if (AMQP_STATUS_OK != res) {
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = res;
|
||||
goto error_out3;
|
||||
}
|
||||
|
||||
if (0 == frame.payload.properties.body_size) {
|
||||
message->body = amqp_empty_bytes;
|
||||
} else {
|
||||
if (SIZE_MAX < frame.payload.properties.body_size) {
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = AMQP_STATUS_NO_MEMORY;
|
||||
goto error_out1;
|
||||
}
|
||||
message->body =
|
||||
amqp_bytes_malloc((size_t)frame.payload.properties.body_size);
|
||||
if (NULL == message->body.bytes) {
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = AMQP_STATUS_NO_MEMORY;
|
||||
goto error_out1;
|
||||
}
|
||||
}
|
||||
|
||||
body_read = 0;
|
||||
body_read_ptr = message->body.bytes;
|
||||
|
||||
while (body_read < message->body.len) {
|
||||
res = amqp_simple_wait_frame_on_channel(state, channel, &frame);
|
||||
if (AMQP_STATUS_OK != res) {
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = res;
|
||||
goto error_out2;
|
||||
}
|
||||
if (AMQP_FRAME_BODY != frame.frame_type) {
|
||||
if (AMQP_FRAME_METHOD == frame.frame_type &&
|
||||
(AMQP_CHANNEL_CLOSE_METHOD == frame.payload.method.id ||
|
||||
AMQP_CONNECTION_CLOSE_METHOD == frame.payload.method.id)) {
|
||||
|
||||
ret.reply_type = AMQP_RESPONSE_SERVER_EXCEPTION;
|
||||
ret.reply = frame.payload.method;
|
||||
} else {
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = AMQP_STATUS_BAD_AMQP_DATA;
|
||||
}
|
||||
goto error_out2;
|
||||
}
|
||||
|
||||
if (body_read + frame.payload.body_fragment.len > message->body.len) {
|
||||
ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
ret.library_error = AMQP_STATUS_BAD_AMQP_DATA;
|
||||
goto error_out2;
|
||||
}
|
||||
|
||||
memcpy(body_read_ptr, frame.payload.body_fragment.bytes,
|
||||
frame.payload.body_fragment.len);
|
||||
|
||||
body_read += frame.payload.body_fragment.len;
|
||||
body_read_ptr += frame.payload.body_fragment.len;
|
||||
}
|
||||
|
||||
ret.reply_type = AMQP_RESPONSE_NORMAL;
|
||||
return ret;
|
||||
|
||||
error_out2:
|
||||
amqp_bytes_free(message->body);
|
||||
error_out3:
|
||||
empty_amqp_pool(&message->pool);
|
||||
error_out1:
|
||||
return ret;
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,195 +0,0 @@
|
|||
/*
|
||||
* Copyright 1996-2014 Daniel Stenberg <daniel@haxx.se>.
|
||||
* Copyright 2014 Michael Steinert
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of a copyright holder shall
|
||||
* not be used in advertising or otherwise to promote the sale, use or other
|
||||
* dealings in this Software without prior written authorization of the
|
||||
* copyright holder.
|
||||
*/
|
||||
|
||||
#include "amqp_hostcheck.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Portable, consistent toupper (remember EBCDIC). Do not use toupper()
|
||||
* because its behavior is altered by the current locale.
|
||||
*/
|
||||
|
||||
static char amqp_raw_toupper(char in) {
|
||||
switch (in) {
|
||||
case 'a':
|
||||
return 'A';
|
||||
case 'b':
|
||||
return 'B';
|
||||
case 'c':
|
||||
return 'C';
|
||||
case 'd':
|
||||
return 'D';
|
||||
case 'e':
|
||||
return 'E';
|
||||
case 'f':
|
||||
return 'F';
|
||||
case 'g':
|
||||
return 'G';
|
||||
case 'h':
|
||||
return 'H';
|
||||
case 'i':
|
||||
return 'I';
|
||||
case 'j':
|
||||
return 'J';
|
||||
case 'k':
|
||||
return 'K';
|
||||
case 'l':
|
||||
return 'L';
|
||||
case 'm':
|
||||
return 'M';
|
||||
case 'n':
|
||||
return 'N';
|
||||
case 'o':
|
||||
return 'O';
|
||||
case 'p':
|
||||
return 'P';
|
||||
case 'q':
|
||||
return 'Q';
|
||||
case 'r':
|
||||
return 'R';
|
||||
case 's':
|
||||
return 'S';
|
||||
case 't':
|
||||
return 'T';
|
||||
case 'u':
|
||||
return 'U';
|
||||
case 'v':
|
||||
return 'V';
|
||||
case 'w':
|
||||
return 'W';
|
||||
case 'x':
|
||||
return 'X';
|
||||
case 'y':
|
||||
return 'Y';
|
||||
case 'z':
|
||||
return 'Z';
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
/*
|
||||
* amqp_raw_equal() is for doing "raw" case insensitive strings. This is meant
|
||||
* to be locale independent and only compare strings we know are safe for
|
||||
* this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
|
||||
* some further explanation to why this function is necessary.
|
||||
*
|
||||
* The function is capable of comparing a-z case insensitively even for
|
||||
* non-ascii.
|
||||
*/
|
||||
|
||||
static int amqp_raw_equal(const char *first, const char *second) {
|
||||
while (*first && *second) {
|
||||
if (amqp_raw_toupper(*first) != amqp_raw_toupper(*second)) {
|
||||
/* get out of the loop as soon as they don't match */
|
||||
break;
|
||||
}
|
||||
first++;
|
||||
second++;
|
||||
}
|
||||
/* we do the comparison here (possibly again), just to make sure that if
|
||||
* the loop above is skipped because one of the strings reached zero, we
|
||||
* must not return this as a successful match
|
||||
*/
|
||||
return (amqp_raw_toupper(*first) == amqp_raw_toupper(*second));
|
||||
}
|
||||
|
||||
static int amqp_raw_nequal(const char *first, const char *second, size_t max) {
|
||||
while (*first && *second && max) {
|
||||
if (amqp_raw_toupper(*first) != amqp_raw_toupper(*second)) {
|
||||
break;
|
||||
}
|
||||
max--;
|
||||
first++;
|
||||
second++;
|
||||
}
|
||||
if (0 == max) {
|
||||
return 1; /* they are equal this far */
|
||||
}
|
||||
return amqp_raw_toupper(*first) == amqp_raw_toupper(*second);
|
||||
}
|
||||
|
||||
/*
|
||||
* Match a hostname against a wildcard pattern.
|
||||
* E.g.
|
||||
* "foo.host.com" matches "*.host.com".
|
||||
*
|
||||
* We use the matching rule described in RFC6125, section 6.4.3.
|
||||
* http://tools.ietf.org/html/rfc6125#section-6.4.3
|
||||
*/
|
||||
|
||||
static amqp_hostcheck_result amqp_hostmatch(const char *hostname,
|
||||
const char *pattern) {
|
||||
const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
|
||||
int wildcard_enabled;
|
||||
size_t prefixlen, suffixlen;
|
||||
pattern_wildcard = strchr(pattern, '*');
|
||||
if (pattern_wildcard == NULL) {
|
||||
return amqp_raw_equal(pattern, hostname) ? AMQP_HCR_MATCH
|
||||
: AMQP_HCR_NO_MATCH;
|
||||
}
|
||||
/* We require at least 2 dots in pattern to avoid too wide wildcard match. */
|
||||
wildcard_enabled = 1;
|
||||
pattern_label_end = strchr(pattern, '.');
|
||||
if (pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL ||
|
||||
pattern_wildcard > pattern_label_end ||
|
||||
amqp_raw_nequal(pattern, "xn--", 4)) {
|
||||
wildcard_enabled = 0;
|
||||
}
|
||||
if (!wildcard_enabled) {
|
||||
return amqp_raw_equal(pattern, hostname) ? AMQP_HCR_MATCH
|
||||
: AMQP_HCR_NO_MATCH;
|
||||
}
|
||||
hostname_label_end = strchr(hostname, '.');
|
||||
if (hostname_label_end == NULL ||
|
||||
!amqp_raw_equal(pattern_label_end, hostname_label_end)) {
|
||||
return AMQP_HCR_NO_MATCH;
|
||||
}
|
||||
/* The wildcard must match at least one character, so the left-most
|
||||
* label of the hostname is at least as large as the left-most label
|
||||
* of the pattern.
|
||||
*/
|
||||
if (hostname_label_end - hostname < pattern_label_end - pattern) {
|
||||
return AMQP_HCR_NO_MATCH;
|
||||
}
|
||||
prefixlen = pattern_wildcard - pattern;
|
||||
suffixlen = pattern_label_end - (pattern_wildcard + 1);
|
||||
return amqp_raw_nequal(pattern, hostname, prefixlen) &&
|
||||
amqp_raw_nequal(pattern_wildcard + 1,
|
||||
hostname_label_end - suffixlen, suffixlen)
|
||||
? AMQP_HCR_MATCH
|
||||
: AMQP_HCR_NO_MATCH;
|
||||
}
|
||||
|
||||
amqp_hostcheck_result amqp_hostcheck(const char *match_pattern,
|
||||
const char *hostname) {
|
||||
/* sanity check */
|
||||
if (!match_pattern || !*match_pattern || !hostname || !*hostname) {
|
||||
return AMQP_HCR_NO_MATCH;
|
||||
}
|
||||
/* trivial case */
|
||||
if (amqp_raw_equal(hostname, match_pattern)) {
|
||||
return AMQP_HCR_MATCH;
|
||||
}
|
||||
return amqp_hostmatch(hostname, match_pattern);
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
#ifndef librabbitmq_amqp_hostcheck_h
|
||||
#define librabbitmq_amqp_hostcheck_h
|
||||
|
||||
/*
|
||||
* Copyright 1996-2014 Daniel Stenberg <daniel@haxx.se>.
|
||||
* Copyright 2014 Michael Steinert
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of a copyright holder shall
|
||||
* not be used in advertising or otherwise to promote the sale, use or other
|
||||
* dealings in this Software without prior written authorization of the
|
||||
* copyright holder.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
AMQP_HCR_NO_MATCH = 0,
|
||||
AMQP_HCR_MATCH = 1
|
||||
} amqp_hostcheck_result;
|
||||
|
||||
/**
|
||||
* Determine whether hostname matches match_pattern.
|
||||
*
|
||||
* match_pattern may include wildcards.
|
||||
*
|
||||
* Match is performed based on the rules set forth in RFC6125 section 6.4.3.
|
||||
* http://tools.ietf.org/html/rfc6125#section-6.4.3
|
||||
*
|
||||
* \param match_pattern RFC6125 compliant pattern
|
||||
* \param hostname to match against
|
||||
* \returns AMQP_HCR_MATCH if its a match, AMQP_HCR_NO_MATCH otherwise.
|
||||
*/
|
||||
amqp_hostcheck_result amqp_hostcheck(const char *match_pattern,
|
||||
const char *hostname);
|
||||
|
||||
#endif
|
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "amqp_private.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
char const *amqp_version(void) { return AMQP_VERSION_STRING; }
|
||||
|
||||
uint32_t amqp_version_number(void) { return AMQP_VERSION; }
|
||||
|
||||
void init_amqp_pool(amqp_pool_t *pool, size_t pagesize) {
|
||||
pool->pagesize = pagesize ? pagesize : 4096;
|
||||
|
||||
pool->pages.num_blocks = 0;
|
||||
pool->pages.blocklist = NULL;
|
||||
|
||||
pool->large_blocks.num_blocks = 0;
|
||||
pool->large_blocks.blocklist = NULL;
|
||||
|
||||
pool->next_page = 0;
|
||||
pool->alloc_block = NULL;
|
||||
pool->alloc_used = 0;
|
||||
}
|
||||
|
||||
static void empty_blocklist(amqp_pool_blocklist_t *x) {
|
||||
int i;
|
||||
|
||||
if (x->blocklist != NULL) {
|
||||
for (i = 0; i < x->num_blocks; i++) {
|
||||
free(x->blocklist[i]);
|
||||
}
|
||||
free(x->blocklist);
|
||||
}
|
||||
x->num_blocks = 0;
|
||||
x->blocklist = NULL;
|
||||
}
|
||||
|
||||
void recycle_amqp_pool(amqp_pool_t *pool) {
|
||||
empty_blocklist(&pool->large_blocks);
|
||||
pool->next_page = 0;
|
||||
pool->alloc_block = NULL;
|
||||
pool->alloc_used = 0;
|
||||
}
|
||||
|
||||
void empty_amqp_pool(amqp_pool_t *pool) {
|
||||
recycle_amqp_pool(pool);
|
||||
empty_blocklist(&pool->pages);
|
||||
}
|
||||
|
||||
/* Returns 1 on success, 0 on failure */
|
||||
static int record_pool_block(amqp_pool_blocklist_t *x, void *block) {
|
||||
size_t blocklistlength = sizeof(void *) * (x->num_blocks + 1);
|
||||
|
||||
if (x->blocklist == NULL) {
|
||||
x->blocklist = malloc(blocklistlength);
|
||||
if (x->blocklist == NULL) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
void *newbl = realloc(x->blocklist, blocklistlength);
|
||||
if (newbl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
x->blocklist = newbl;
|
||||
}
|
||||
|
||||
x->blocklist[x->num_blocks] = block;
|
||||
x->num_blocks++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *amqp_pool_alloc(amqp_pool_t *pool, size_t amount) {
|
||||
if (amount == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
amount = (amount + 7) & (~7); /* round up to nearest 8-byte boundary */
|
||||
|
||||
if (amount > pool->pagesize) {
|
||||
void *result = calloc(1, amount);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!record_pool_block(&pool->large_blocks, result)) {
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (pool->alloc_block != NULL) {
|
||||
assert(pool->alloc_used <= pool->pagesize);
|
||||
|
||||
if (pool->alloc_used + amount <= pool->pagesize) {
|
||||
void *result = pool->alloc_block + pool->alloc_used;
|
||||
pool->alloc_used += amount;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (pool->next_page >= pool->pages.num_blocks) {
|
||||
pool->alloc_block = calloc(1, pool->pagesize);
|
||||
if (pool->alloc_block == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!record_pool_block(&pool->pages, pool->alloc_block)) {
|
||||
return NULL;
|
||||
}
|
||||
pool->next_page = pool->pages.num_blocks;
|
||||
} else {
|
||||
pool->alloc_block = pool->pages.blocklist[pool->next_page];
|
||||
pool->next_page++;
|
||||
}
|
||||
|
||||
pool->alloc_used = amount;
|
||||
|
||||
return pool->alloc_block;
|
||||
}
|
||||
|
||||
void amqp_pool_alloc_bytes(amqp_pool_t *pool, size_t amount,
|
||||
amqp_bytes_t *output) {
|
||||
output->len = amount;
|
||||
output->bytes = amqp_pool_alloc(pool, amount);
|
||||
}
|
||||
|
||||
amqp_bytes_t amqp_cstring_bytes(char const *cstr) {
|
||||
amqp_bytes_t result;
|
||||
result.len = strlen(cstr);
|
||||
result.bytes = (void *)cstr;
|
||||
return result;
|
||||
}
|
||||
|
||||
amqp_bytes_t amqp_bytes_malloc_dup(amqp_bytes_t src) {
|
||||
amqp_bytes_t result;
|
||||
result.len = src.len;
|
||||
result.bytes = malloc(src.len);
|
||||
if (result.bytes != NULL) {
|
||||
memcpy(result.bytes, src.bytes, src.len);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
amqp_bytes_t amqp_bytes_malloc(size_t amount) {
|
||||
amqp_bytes_t result;
|
||||
result.len = amount;
|
||||
result.bytes = malloc(amount); /* will return NULL if it fails */
|
||||
return result;
|
||||
}
|
||||
|
||||
void amqp_bytes_free(amqp_bytes_t bytes) { free(bytes.bytes); }
|
||||
|
||||
amqp_pool_t *amqp_get_or_create_channel_pool(amqp_connection_state_t state,
|
||||
amqp_channel_t channel) {
|
||||
amqp_pool_table_entry_t *entry;
|
||||
size_t index = channel % POOL_TABLE_SIZE;
|
||||
|
||||
entry = state->pool_table[index];
|
||||
|
||||
for (; NULL != entry; entry = entry->next) {
|
||||
if (channel == entry->channel) {
|
||||
return &entry->pool;
|
||||
}
|
||||
}
|
||||
|
||||
entry = malloc(sizeof(amqp_pool_table_entry_t));
|
||||
if (NULL == entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entry->channel = channel;
|
||||
entry->next = state->pool_table[index];
|
||||
state->pool_table[index] = entry;
|
||||
|
||||
init_amqp_pool(&entry->pool, state->frame_max);
|
||||
|
||||
return &entry->pool;
|
||||
}
|
||||
|
||||
amqp_pool_t *amqp_get_channel_pool(amqp_connection_state_t state,
|
||||
amqp_channel_t channel) {
|
||||
amqp_pool_table_entry_t *entry;
|
||||
size_t index = channel % POOL_TABLE_SIZE;
|
||||
|
||||
entry = state->pool_table[index];
|
||||
|
||||
for (; NULL != entry; entry = entry->next) {
|
||||
if (channel == entry->channel) {
|
||||
return &entry->pool;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int amqp_bytes_equal(amqp_bytes_t r, amqp_bytes_t l) {
|
||||
if (r.len == l.len &&
|
||||
(r.bytes == l.bytes || 0 == memcmp(r.bytes, l.bytes, r.len))) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,704 +0,0 @@
|
|||
/*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2014 Alan Antonuk.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Michael Steinert are Copyright (c) 2012-2014 Michael
|
||||
* Steinert. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "amqp_openssl_bio.h"
|
||||
#include "amqp_openssl_hostname_validation.h"
|
||||
#include "amqp_private.h"
|
||||
#include "amqp_socket.h"
|
||||
#include "amqp_ssl_socket.h"
|
||||
#include "amqp_time.h"
|
||||
#include "threads.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/engine.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int initialize_ssl_and_increment_connections(void);
|
||||
static int decrement_ssl_connections(void);
|
||||
|
||||
static unsigned long ssl_threadid_callback(void);
|
||||
static void ssl_locking_callback(int mode, int n, const char *file, int line);
|
||||
static pthread_mutex_t *amqp_openssl_lockarray = NULL;
|
||||
|
||||
static pthread_mutex_t openssl_init_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static amqp_boolean_t do_initialize_openssl = 1;
|
||||
static amqp_boolean_t openssl_initialized = 0;
|
||||
static amqp_boolean_t openssl_bio_initialized = 0;
|
||||
static int openssl_connections = 0;
|
||||
|
||||
#define CHECK_SUCCESS(condition) \
|
||||
do { \
|
||||
int check_success_ret = (condition); \
|
||||
if (check_success_ret) { \
|
||||
amqp_abort("Check %s failed <%d>: %s", #condition, check_success_ret, \
|
||||
strerror(check_success_ret)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct amqp_ssl_socket_t {
|
||||
const struct amqp_socket_class_t *klass;
|
||||
SSL_CTX *ctx;
|
||||
int sockfd;
|
||||
SSL *ssl;
|
||||
amqp_boolean_t verify_peer;
|
||||
amqp_boolean_t verify_hostname;
|
||||
int internal_error;
|
||||
};
|
||||
|
||||
static ssize_t amqp_ssl_socket_send(void *base, const void *buf, size_t len,
|
||||
AMQP_UNUSED int flags) {
|
||||
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
|
||||
int res;
|
||||
if (-1 == self->sockfd) {
|
||||
return AMQP_STATUS_SOCKET_CLOSED;
|
||||
}
|
||||
|
||||
/* SSL_write takes an int for length of buffer, protect against len being
|
||||
* larger than larger than what SSL_write can take */
|
||||
if (len > INT_MAX) {
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
self->internal_error = 0;
|
||||
|
||||
/* This will only return on error, or once the whole buffer has been
|
||||
* written to the SSL stream. See SSL_MODE_ENABLE_PARTIAL_WRITE */
|
||||
res = SSL_write(self->ssl, buf, (int)len);
|
||||
if (0 >= res) {
|
||||
self->internal_error = SSL_get_error(self->ssl, res);
|
||||
/* TODO: Close connection if it isn't already? */
|
||||
/* TODO: Possibly be more intelligent in reporting WHAT went wrong */
|
||||
switch (self->internal_error) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
res = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD;
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
res = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
res = AMQP_STATUS_CONNECTION_CLOSED;
|
||||
break;
|
||||
default:
|
||||
res = AMQP_STATUS_SSL_ERROR;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
self->internal_error = 0;
|
||||
}
|
||||
|
||||
return (ssize_t)res;
|
||||
}
|
||||
|
||||
static ssize_t amqp_ssl_socket_recv(void *base, void *buf, size_t len,
|
||||
AMQP_UNUSED int flags) {
|
||||
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
|
||||
int received;
|
||||
if (-1 == self->sockfd) {
|
||||
return AMQP_STATUS_SOCKET_CLOSED;
|
||||
}
|
||||
|
||||
/* SSL_read takes an int for length of buffer, protect against len being
|
||||
* larger than larger than what SSL_read can take */
|
||||
if (len > INT_MAX) {
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
self->internal_error = 0;
|
||||
|
||||
received = SSL_read(self->ssl, buf, (int)len);
|
||||
if (0 >= received) {
|
||||
self->internal_error = SSL_get_error(self->ssl, received);
|
||||
switch (self->internal_error) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
received = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD;
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
received = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
received = AMQP_STATUS_CONNECTION_CLOSED;
|
||||
break;
|
||||
default:
|
||||
received = AMQP_STATUS_SSL_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (ssize_t)received;
|
||||
}
|
||||
|
||||
static int amqp_ssl_socket_open(void *base, const char *host, int port,
|
||||
struct timeval *timeout) {
|
||||
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
|
||||
long result;
|
||||
int status;
|
||||
amqp_time_t deadline;
|
||||
X509 *cert;
|
||||
BIO *bio;
|
||||
if (-1 != self->sockfd) {
|
||||
return AMQP_STATUS_SOCKET_INUSE;
|
||||
}
|
||||
ERR_clear_error();
|
||||
|
||||
self->ssl = SSL_new(self->ctx);
|
||||
if (!self->ssl) {
|
||||
self->internal_error = ERR_peek_error();
|
||||
status = AMQP_STATUS_SSL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = amqp_time_from_now(&deadline, timeout);
|
||||
if (AMQP_STATUS_OK != status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
self->sockfd = amqp_open_socket_inner(host, port, deadline);
|
||||
if (0 > self->sockfd) {
|
||||
status = self->sockfd;
|
||||
self->internal_error = amqp_os_socket_error();
|
||||
self->sockfd = -1;
|
||||
goto error_out1;
|
||||
}
|
||||
|
||||
bio = BIO_new(amqp_openssl_bio());
|
||||
if (!bio) {
|
||||
status = AMQP_STATUS_NO_MEMORY;
|
||||
goto error_out2;
|
||||
}
|
||||
|
||||
BIO_set_fd(bio, self->sockfd, BIO_NOCLOSE);
|
||||
SSL_set_bio(self->ssl, bio, bio);
|
||||
|
||||
status = SSL_set_tlsext_host_name(self->ssl, host);
|
||||
if (!status) {
|
||||
self->internal_error = SSL_get_error(self->ssl, status);
|
||||
status = AMQP_STATUS_SSL_ERROR;
|
||||
goto error_out2;
|
||||
}
|
||||
|
||||
start_connect:
|
||||
status = SSL_connect(self->ssl);
|
||||
if (status != 1) {
|
||||
self->internal_error = SSL_get_error(self->ssl, status);
|
||||
switch (self->internal_error) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
status = amqp_poll(self->sockfd, AMQP_SF_POLLIN, deadline);
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
status = amqp_poll(self->sockfd, AMQP_SF_POLLOUT, deadline);
|
||||
break;
|
||||
default:
|
||||
status = AMQP_STATUS_SSL_CONNECTION_FAILED;
|
||||
}
|
||||
if (AMQP_STATUS_OK == status) {
|
||||
goto start_connect;
|
||||
}
|
||||
goto error_out2;
|
||||
}
|
||||
|
||||
cert = SSL_get_peer_certificate(self->ssl);
|
||||
|
||||
if (self->verify_peer) {
|
||||
if (!cert) {
|
||||
self->internal_error = 0;
|
||||
status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED;
|
||||
goto error_out3;
|
||||
}
|
||||
|
||||
result = SSL_get_verify_result(self->ssl);
|
||||
if (X509_V_OK != result) {
|
||||
self->internal_error = result;
|
||||
status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED;
|
||||
goto error_out4;
|
||||
}
|
||||
}
|
||||
if (self->verify_hostname) {
|
||||
if (!cert) {
|
||||
self->internal_error = 0;
|
||||
status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED;
|
||||
goto error_out3;
|
||||
}
|
||||
|
||||
if (AMQP_HVR_MATCH_FOUND != amqp_ssl_validate_hostname(host, cert)) {
|
||||
self->internal_error = 0;
|
||||
status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED;
|
||||
goto error_out4;
|
||||
}
|
||||
}
|
||||
|
||||
X509_free(cert);
|
||||
self->internal_error = 0;
|
||||
status = AMQP_STATUS_OK;
|
||||
|
||||
exit:
|
||||
return status;
|
||||
|
||||
error_out4:
|
||||
X509_free(cert);
|
||||
error_out3:
|
||||
SSL_shutdown(self->ssl);
|
||||
error_out2:
|
||||
amqp_os_socket_close(self->sockfd);
|
||||
self->sockfd = -1;
|
||||
error_out1:
|
||||
SSL_free(self->ssl);
|
||||
self->ssl = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static int amqp_ssl_socket_close(void *base, amqp_socket_close_enum force) {
|
||||
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
|
||||
|
||||
if (-1 == self->sockfd) {
|
||||
return AMQP_STATUS_SOCKET_CLOSED;
|
||||
}
|
||||
|
||||
if (AMQP_SC_NONE == force) {
|
||||
/* don't try too hard to shutdown the connection */
|
||||
SSL_shutdown(self->ssl);
|
||||
}
|
||||
|
||||
SSL_free(self->ssl);
|
||||
self->ssl = NULL;
|
||||
|
||||
if (amqp_os_socket_close(self->sockfd)) {
|
||||
return AMQP_STATUS_SOCKET_ERROR;
|
||||
}
|
||||
self->sockfd = -1;
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
static int amqp_ssl_socket_get_sockfd(void *base) {
|
||||
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
|
||||
return self->sockfd;
|
||||
}
|
||||
|
||||
static void amqp_ssl_socket_delete(void *base) {
|
||||
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
|
||||
|
||||
if (self) {
|
||||
amqp_ssl_socket_close(self, AMQP_SC_NONE);
|
||||
|
||||
SSL_CTX_free(self->ctx);
|
||||
free(self);
|
||||
}
|
||||
decrement_ssl_connections();
|
||||
}
|
||||
|
||||
static const struct amqp_socket_class_t amqp_ssl_socket_class = {
|
||||
amqp_ssl_socket_send, /* send */
|
||||
amqp_ssl_socket_recv, /* recv */
|
||||
amqp_ssl_socket_open, /* open */
|
||||
amqp_ssl_socket_close, /* close */
|
||||
amqp_ssl_socket_get_sockfd, /* get_sockfd */
|
||||
amqp_ssl_socket_delete /* delete */
|
||||
};
|
||||
|
||||
amqp_socket_t *amqp_ssl_socket_new(amqp_connection_state_t state) {
|
||||
struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self));
|
||||
int status;
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->sockfd = -1;
|
||||
self->klass = &amqp_ssl_socket_class;
|
||||
self->verify_peer = 1;
|
||||
self->verify_hostname = 1;
|
||||
|
||||
status = initialize_ssl_and_increment_connections();
|
||||
if (status) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
self->ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (!self->ctx) {
|
||||
goto error;
|
||||
}
|
||||
/* Disable SSLv2 and SSLv3 */
|
||||
SSL_CTX_set_options(self->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
|
||||
amqp_set_socket(state, (amqp_socket_t *)self);
|
||||
|
||||
return (amqp_socket_t *)self;
|
||||
error:
|
||||
amqp_ssl_socket_delete((amqp_socket_t *)self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int amqp_ssl_socket_set_cacert(amqp_socket_t *base, const char *cacert) {
|
||||
int status;
|
||||
struct amqp_ssl_socket_t *self;
|
||||
if (base->klass != &amqp_ssl_socket_class) {
|
||||
amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
|
||||
}
|
||||
self = (struct amqp_ssl_socket_t *)base;
|
||||
status = SSL_CTX_load_verify_locations(self->ctx, cacert, NULL);
|
||||
if (1 != status) {
|
||||
return AMQP_STATUS_SSL_ERROR;
|
||||
}
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
int amqp_ssl_socket_set_key(amqp_socket_t *base, const char *cert,
|
||||
const char *key) {
|
||||
int status;
|
||||
struct amqp_ssl_socket_t *self;
|
||||
if (base->klass != &amqp_ssl_socket_class) {
|
||||
amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
|
||||
}
|
||||
self = (struct amqp_ssl_socket_t *)base;
|
||||
status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
|
||||
if (1 != status) {
|
||||
return AMQP_STATUS_SSL_ERROR;
|
||||
}
|
||||
status = SSL_CTX_use_PrivateKey_file(self->ctx, key, SSL_FILETYPE_PEM);
|
||||
if (1 != status) {
|
||||
return AMQP_STATUS_SSL_ERROR;
|
||||
}
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
static int password_cb(AMQP_UNUSED char *buffer, AMQP_UNUSED int length,
|
||||
AMQP_UNUSED int rwflag, AMQP_UNUSED void *user_data) {
|
||||
amqp_abort("rabbitmq-c does not support password protected keys");
|
||||
}
|
||||
|
||||
int amqp_ssl_socket_set_key_buffer(amqp_socket_t *base, const char *cert,
|
||||
const void *key, size_t n) {
|
||||
int status = AMQP_STATUS_OK;
|
||||
BIO *buf = NULL;
|
||||
RSA *rsa = NULL;
|
||||
struct amqp_ssl_socket_t *self;
|
||||
if (base->klass != &amqp_ssl_socket_class) {
|
||||
amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
|
||||
}
|
||||
if (n > INT_MAX) {
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
self = (struct amqp_ssl_socket_t *)base;
|
||||
status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
|
||||
if (1 != status) {
|
||||
return AMQP_STATUS_SSL_ERROR;
|
||||
}
|
||||
buf = BIO_new_mem_buf((void *)key, (int)n);
|
||||
if (!buf) {
|
||||
goto error;
|
||||
}
|
||||
rsa = PEM_read_bio_RSAPrivateKey(buf, NULL, password_cb, NULL);
|
||||
if (!rsa) {
|
||||
goto error;
|
||||
}
|
||||
status = SSL_CTX_use_RSAPrivateKey(self->ctx, rsa);
|
||||
if (1 != status) {
|
||||
goto error;
|
||||
}
|
||||
exit:
|
||||
BIO_vfree(buf);
|
||||
RSA_free(rsa);
|
||||
return status;
|
||||
error:
|
||||
status = AMQP_STATUS_SSL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
int amqp_ssl_socket_set_cert(amqp_socket_t *base, const char *cert) {
|
||||
int status;
|
||||
struct amqp_ssl_socket_t *self;
|
||||
if (base->klass != &amqp_ssl_socket_class) {
|
||||
amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
|
||||
}
|
||||
self = (struct amqp_ssl_socket_t *)base;
|
||||
status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
|
||||
if (1 != status) {
|
||||
return AMQP_STATUS_SSL_ERROR;
|
||||
}
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
void amqp_ssl_socket_set_verify(amqp_socket_t *base, amqp_boolean_t verify) {
|
||||
amqp_ssl_socket_set_verify_peer(base, verify);
|
||||
amqp_ssl_socket_set_verify_hostname(base, verify);
|
||||
}
|
||||
|
||||
void amqp_ssl_socket_set_verify_peer(amqp_socket_t *base,
|
||||
amqp_boolean_t verify) {
|
||||
struct amqp_ssl_socket_t *self;
|
||||
if (base->klass != &amqp_ssl_socket_class) {
|
||||
amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
|
||||
}
|
||||
self = (struct amqp_ssl_socket_t *)base;
|
||||
self->verify_peer = verify;
|
||||
}
|
||||
|
||||
void amqp_ssl_socket_set_verify_hostname(amqp_socket_t *base,
|
||||
amqp_boolean_t verify) {
|
||||
struct amqp_ssl_socket_t *self;
|
||||
if (base->klass != &amqp_ssl_socket_class) {
|
||||
amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
|
||||
}
|
||||
self = (struct amqp_ssl_socket_t *)base;
|
||||
self->verify_hostname = verify;
|
||||
}
|
||||
|
||||
int amqp_ssl_socket_set_ssl_versions(amqp_socket_t *base,
|
||||
amqp_tls_version_t min,
|
||||
amqp_tls_version_t max) {
|
||||
struct amqp_ssl_socket_t *self;
|
||||
if (base->klass != &amqp_ssl_socket_class) {
|
||||
amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
|
||||
}
|
||||
self = (struct amqp_ssl_socket_t *)base;
|
||||
|
||||
{
|
||||
long clear_options;
|
||||
long set_options = 0;
|
||||
#if defined(SSL_OP_NO_TLSv1_2)
|
||||
amqp_tls_version_t max_supported = AMQP_TLSv1_2;
|
||||
clear_options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
|
||||
#elif defined(SSL_OP_NO_TLSv1_1)
|
||||
amqp_tls_version_t max_supported = AMQP_TLSv1_1;
|
||||
clear_options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
|
||||
#elif defined(SSL_OP_NO_TLSv1)
|
||||
amqp_tls_version_t max_supported = AMQP_TLSv1;
|
||||
clear_options = SSL_OP_NO_TLSv1;
|
||||
#else
|
||||
#error "Need a version of OpenSSL that can support TLSv1 or greater."
|
||||
#endif
|
||||
|
||||
if (AMQP_TLSvLATEST == max) {
|
||||
max = max_supported;
|
||||
}
|
||||
if (AMQP_TLSvLATEST == min) {
|
||||
min = max_supported;
|
||||
}
|
||||
|
||||
if (min > max) {
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (max > max_supported || min > max_supported) {
|
||||
return AMQP_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (min > AMQP_TLSv1) {
|
||||
set_options |= SSL_OP_NO_TLSv1;
|
||||
}
|
||||
#ifdef SSL_OP_NO_TLSv1_1
|
||||
if (min > AMQP_TLSv1_1 || max < AMQP_TLSv1_1) {
|
||||
set_options |= SSL_OP_NO_TLSv1_1;
|
||||
}
|
||||
#endif
|
||||
#ifdef SSL_OP_NO_TLSv1_2
|
||||
if (max < AMQP_TLSv1_2) {
|
||||
set_options |= SSL_OP_NO_TLSv1_2;
|
||||
}
|
||||
#endif
|
||||
SSL_CTX_clear_options(self->ctx, clear_options);
|
||||
SSL_CTX_set_options(self->ctx, set_options);
|
||||
}
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
void amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize) {
|
||||
CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
|
||||
|
||||
if (openssl_connections == 0 && !openssl_initialized) {
|
||||
do_initialize_openssl = do_initialize;
|
||||
}
|
||||
CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
|
||||
}
|
||||
|
||||
static unsigned long ssl_threadid_callback(void) {
|
||||
return (unsigned long)pthread_self();
|
||||
}
|
||||
|
||||
static void ssl_locking_callback(int mode, int n, AMQP_UNUSED const char *file,
|
||||
AMQP_UNUSED int line) {
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
CHECK_SUCCESS(pthread_mutex_lock(&amqp_openssl_lockarray[n]));
|
||||
} else {
|
||||
CHECK_SUCCESS(pthread_mutex_unlock(&amqp_openssl_lockarray[n]));
|
||||
}
|
||||
}
|
||||
|
||||
static int setup_openssl(void) {
|
||||
int status;
|
||||
|
||||
int i;
|
||||
amqp_openssl_lockarray = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t));
|
||||
if (!amqp_openssl_lockarray) {
|
||||
status = AMQP_STATUS_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
if (pthread_mutex_init(&amqp_openssl_lockarray[i], NULL)) {
|
||||
int j;
|
||||
for (j = 0; j < i; j++) {
|
||||
pthread_mutex_destroy(&amqp_openssl_lockarray[j]);
|
||||
}
|
||||
free(amqp_openssl_lockarray);
|
||||
status = AMQP_STATUS_SSL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
CRYPTO_set_id_callback(ssl_threadid_callback);
|
||||
CRYPTO_set_locking_callback(ssl_locking_callback);
|
||||
|
||||
#ifdef AMQP_OPENSSL_V110
|
||||
if (CONF_modules_load_file(NULL, "rabbitmq-c", CONF_MFLAGS_DEFAULT_SECTION) <=
|
||||
0) {
|
||||
status = AMQP_STATUS_SSL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
OPENSSL_config(NULL);
|
||||
#endif
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
|
||||
status = AMQP_STATUS_OK;
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
int amqp_initialize_ssl_library(void) {
|
||||
int status;
|
||||
CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
|
||||
|
||||
if (!openssl_initialized) {
|
||||
status = setup_openssl();
|
||||
if (status) {
|
||||
goto out;
|
||||
}
|
||||
openssl_initialized = 1;
|
||||
}
|
||||
|
||||
status = AMQP_STATUS_OK;
|
||||
out:
|
||||
CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
|
||||
return status;
|
||||
}
|
||||
|
||||
static int initialize_ssl_and_increment_connections() {
|
||||
int status;
|
||||
CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
|
||||
|
||||
if (do_initialize_openssl && !openssl_initialized) {
|
||||
status = setup_openssl();
|
||||
if (status) {
|
||||
goto exit;
|
||||
}
|
||||
openssl_initialized = 1;
|
||||
}
|
||||
|
||||
if (!openssl_bio_initialized) {
|
||||
status = amqp_openssl_bio_init();
|
||||
if (status) {
|
||||
goto exit;
|
||||
}
|
||||
openssl_bio_initialized = 1;
|
||||
}
|
||||
|
||||
openssl_connections += 1;
|
||||
status = AMQP_STATUS_OK;
|
||||
exit:
|
||||
CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
|
||||
return status;
|
||||
}
|
||||
|
||||
static int decrement_ssl_connections(void) {
|
||||
CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
|
||||
|
||||
if (openssl_connections > 0) {
|
||||
openssl_connections--;
|
||||
}
|
||||
|
||||
CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
int amqp_uninitialize_ssl_library(void) {
|
||||
int status;
|
||||
CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
|
||||
|
||||
if (openssl_connections > 0) {
|
||||
status = AMQP_STATUS_SOCKET_INUSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
amqp_openssl_bio_destroy();
|
||||
openssl_bio_initialized = 0;
|
||||
|
||||
#ifndef AMQP_OPENSSL_V110
|
||||
ERR_remove_state(0);
|
||||
#endif
|
||||
|
||||
#ifndef LIBRESSL_VERSION_NUMBER
|
||||
FIPS_mode_set(0);
|
||||
#endif
|
||||
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
CRYPTO_set_id_callback(NULL);
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
pthread_mutex_destroy(&amqp_openssl_lockarray[i]);
|
||||
}
|
||||
free(amqp_openssl_lockarray);
|
||||
}
|
||||
|
||||
ENGINE_cleanup();
|
||||
CONF_modules_free();
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
ERR_free_strings();
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10002003L) && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
SSL_COMP_free_compression_methods();
|
||||
#endif
|
||||
|
||||
openssl_initialized = 0;
|
||||
|
||||
status = AMQP_STATUS_OK;
|
||||
out:
|
||||
CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
|
||||
return status;
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2017 Alan Antonuk.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "amqp_openssl_bio.h"
|
||||
#include "amqp_socket.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef MSG_NOSIGNAL
|
||||
#define AMQP_USE_AMQP_BIO
|
||||
#endif
|
||||
|
||||
static int amqp_ssl_bio_initialized = 0;
|
||||
|
||||
#ifdef AMQP_USE_AMQP_BIO
|
||||
|
||||
static BIO_METHOD *amqp_bio_method;
|
||||
|
||||
static int amqp_openssl_bio_should_retry(int res) {
|
||||
if (res == -1) {
|
||||
int err = amqp_os_socket_error();
|
||||
if (
|
||||
#ifdef EWOULDBLOCK
|
||||
err == EWOULDBLOCK ||
|
||||
#endif
|
||||
#ifdef WSAEWOULDBLOCK
|
||||
err == WSAEWOULDBLOCK ||
|
||||
#endif
|
||||
#ifdef ENOTCONN
|
||||
err == ENOTCONN ||
|
||||
#endif
|
||||
#ifdef EINTR
|
||||
err == EINTR ||
|
||||
#endif
|
||||
#ifdef EAGAIN
|
||||
err == EAGAIN ||
|
||||
#endif
|
||||
#ifdef EPROTO
|
||||
err == EPROTO ||
|
||||
#endif
|
||||
#ifdef EINPROGRESS
|
||||
err == EINPROGRESS ||
|
||||
#endif
|
||||
#ifdef EALREADY
|
||||
err == EALREADY ||
|
||||
#endif
|
||||
0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amqp_openssl_bio_write(BIO *b, const char *in, int inl) {
|
||||
int flags = 0;
|
||||
int fd;
|
||||
int res;
|
||||
|
||||
#ifdef MSG_NOSIGNAL
|
||||
flags |= MSG_NOSIGNAL;
|
||||
#endif
|
||||
|
||||
BIO_get_fd(b, &fd);
|
||||
res = send(fd, in, inl, flags);
|
||||
|
||||
BIO_clear_retry_flags(b);
|
||||
if (res <= 0 && amqp_openssl_bio_should_retry(res)) {
|
||||
BIO_set_retry_write(b);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int amqp_openssl_bio_read(BIO *b, char *out, int outl) {
|
||||
int flags = 0;
|
||||
int fd;
|
||||
int res;
|
||||
|
||||
#ifdef MSG_NOSIGNAL
|
||||
flags |= MSG_NOSIGNAL;
|
||||
#endif
|
||||
|
||||
BIO_get_fd(b, &fd);
|
||||
res = recv(fd, out, outl, flags);
|
||||
|
||||
BIO_clear_retry_flags(b);
|
||||
if (res <= 0 && amqp_openssl_bio_should_retry(res)) {
|
||||
BIO_set_retry_read(b);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifndef AMQP_OPENSSL_V110
|
||||
static int BIO_meth_set_write(BIO_METHOD *biom,
|
||||
int (*wfn)(BIO *, const char *, int)) {
|
||||
biom->bwrite = wfn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int BIO_meth_set_read(BIO_METHOD *biom, int (*rfn)(BIO *, char *, int)) {
|
||||
biom->bread = rfn;
|
||||
return 0;
|
||||
}
|
||||
#endif /* AQP_OPENSSL_V110 */
|
||||
#endif /* AMQP_USE_AMQP_BIO */
|
||||
|
||||
int amqp_openssl_bio_init(void) {
|
||||
assert(!amqp_ssl_bio_initialized);
|
||||
#ifdef AMQP_USE_AMQP_BIO
|
||||
#ifdef AMQP_OPENSSL_V110
|
||||
if (!(amqp_bio_method = BIO_meth_new(BIO_TYPE_SOCKET, "amqp_bio_method"))) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
// casting away const is necessary until
|
||||
// https://github.com/openssl/openssl/pull/2181/, which is targeted for
|
||||
// openssl 1.1.1
|
||||
BIO_METHOD *meth = (BIO_METHOD *)BIO_s_socket();
|
||||
BIO_meth_set_create(amqp_bio_method, BIO_meth_get_create(meth));
|
||||
BIO_meth_set_destroy(amqp_bio_method, BIO_meth_get_destroy(meth));
|
||||
BIO_meth_set_ctrl(amqp_bio_method, BIO_meth_get_ctrl(meth));
|
||||
BIO_meth_set_callback_ctrl(amqp_bio_method, BIO_meth_get_callback_ctrl(meth));
|
||||
BIO_meth_set_read(amqp_bio_method, BIO_meth_get_read(meth));
|
||||
BIO_meth_set_write(amqp_bio_method, BIO_meth_get_write(meth));
|
||||
BIO_meth_set_gets(amqp_bio_method, BIO_meth_get_gets(meth));
|
||||
BIO_meth_set_puts(amqp_bio_method, BIO_meth_get_puts(meth));
|
||||
#else
|
||||
if (!(amqp_bio_method = OPENSSL_malloc(sizeof(BIO_METHOD)))) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(amqp_bio_method, BIO_s_socket(), sizeof(BIO_METHOD));
|
||||
#endif
|
||||
BIO_meth_set_write(amqp_bio_method, amqp_openssl_bio_write);
|
||||
BIO_meth_set_read(amqp_bio_method, amqp_openssl_bio_read);
|
||||
#endif
|
||||
|
||||
amqp_ssl_bio_initialized = 1;
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
void amqp_openssl_bio_destroy(void) {
|
||||
assert(amqp_ssl_bio_initialized);
|
||||
#ifdef AMQP_USE_AMQP_BIO
|
||||
#ifdef AMQP_OPENSSL_V110
|
||||
BIO_meth_free(amqp_bio_method);
|
||||
#else
|
||||
OPENSSL_free(amqp_bio_method);
|
||||
#endif
|
||||
amqp_bio_method = NULL;
|
||||
#endif
|
||||
amqp_ssl_bio_initialized = 0;
|
||||
}
|
||||
|
||||
BIO_METHOD_PTR amqp_openssl_bio(void) {
|
||||
assert(amqp_ssl_bio_initialized);
|
||||
#ifdef AMQP_USE_AMQP_BIO
|
||||
return amqp_bio_method;
|
||||
#else
|
||||
return BIO_s_socket();
|
||||
#endif
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2017 Alan Antonuk.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef AMQP_OPENSSL_BIO
|
||||
#define AMQP_OPENSSL_BIO
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
int amqp_openssl_bio_init(void);
|
||||
|
||||
void amqp_openssl_bio_destroy(void);
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
#define AMQP_OPENSSL_V110
|
||||
#endif
|
||||
|
||||
#ifdef AMQP_OPENSSL_V110
|
||||
typedef const BIO_METHOD *BIO_METHOD_PTR;
|
||||
#else
|
||||
typedef BIO_METHOD *BIO_METHOD_PTR;
|
||||
#endif
|
||||
|
||||
BIO_METHOD_PTR amqp_openssl_bio(void);
|
||||
|
||||
#endif /* ifndef AMQP_OPENSSL_BIO */
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012, iSEC Partners.
|
||||
* Copyright (C) 2015 Alan Antonuk.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of a copyright holder shall
|
||||
* not be used in advertising or otherwise to promote the sale, use or other
|
||||
* dealings in this Software without prior written authorization of the
|
||||
* copyright holder.
|
||||
*/
|
||||
|
||||
/* Originally from:
|
||||
* https://github.com/iSECPartners/ssl-conservatory
|
||||
* https://wiki.openssl.org/index.php/Hostname_validation
|
||||
*/
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#include "amqp_hostcheck.h"
|
||||
#include "amqp_openssl_bio.h"
|
||||
#include "amqp_openssl_hostname_validation.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define HOSTNAME_MAX_SIZE 255
|
||||
|
||||
/**
|
||||
* Tries to find a match for hostname in the certificate's Common Name field.
|
||||
*
|
||||
* Returns AMQP_HVR_MATCH_FOUND if a match was found.
|
||||
* Returns AMQP_HVR_MATCH_NOT_FOUND if no matches were found.
|
||||
* Returns AMQP_HVR_MALFORMED_CERTIFICATE if the Common Name had a NUL character
|
||||
* embedded in it.
|
||||
* Returns AMQP_HVR_ERROR if the Common Name could not be extracted.
|
||||
*/
|
||||
static amqp_hostname_validation_result amqp_matches_common_name(
|
||||
const char *hostname, const X509 *server_cert) {
|
||||
int common_name_loc = -1;
|
||||
X509_NAME_ENTRY *common_name_entry = NULL;
|
||||
ASN1_STRING *common_name_asn1 = NULL;
|
||||
const char *common_name_str = NULL;
|
||||
|
||||
// Find the position of the CN field in the Subject field of the certificate
|
||||
common_name_loc = X509_NAME_get_index_by_NID(
|
||||
X509_get_subject_name((X509 *)server_cert), NID_commonName, -1);
|
||||
if (common_name_loc < 0) {
|
||||
return AMQP_HVR_ERROR;
|
||||
}
|
||||
|
||||
// Extract the CN field
|
||||
common_name_entry = X509_NAME_get_entry(
|
||||
X509_get_subject_name((X509 *)server_cert), common_name_loc);
|
||||
if (common_name_entry == NULL) {
|
||||
return AMQP_HVR_ERROR;
|
||||
}
|
||||
|
||||
// Convert the CN field to a C string
|
||||
common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
|
||||
if (common_name_asn1 == NULL) {
|
||||
return AMQP_HVR_ERROR;
|
||||
}
|
||||
|
||||
#ifdef AMQP_OPENSSL_V110
|
||||
common_name_str = (const char *)ASN1_STRING_get0_data(common_name_asn1);
|
||||
#else
|
||||
common_name_str = (char *)ASN1_STRING_data(common_name_asn1);
|
||||
#endif
|
||||
|
||||
// Make sure there isn't an embedded NUL character in the CN
|
||||
if ((size_t)ASN1_STRING_length(common_name_asn1) != strlen(common_name_str)) {
|
||||
return AMQP_HVR_MALFORMED_CERTIFICATE;
|
||||
}
|
||||
|
||||
// Compare expected hostname with the CN
|
||||
if (amqp_hostcheck(common_name_str, hostname) == AMQP_HCR_MATCH) {
|
||||
return AMQP_HVR_MATCH_FOUND;
|
||||
} else {
|
||||
return AMQP_HVR_MATCH_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find a match for hostname in the certificate's Subject Alternative
|
||||
* Name extension.
|
||||
*
|
||||
* Returns AMQP_HVR_MATCH_FOUND if a match was found.
|
||||
* Returns AMQP_HVR_MATCH_NOT_FOUND if no matches were found.
|
||||
* Returns AMQP_HVR_MALFORMED_CERTIFICATE if any of the hostnames had a NUL
|
||||
* character embedded in it.
|
||||
* Returns AMQP_HVR_NO_SAN_PRESENT if the SAN extension was not present in the
|
||||
* certificate.
|
||||
*/
|
||||
static amqp_hostname_validation_result amqp_matches_subject_alternative_name(
|
||||
const char *hostname, const X509 *server_cert) {
|
||||
amqp_hostname_validation_result result = AMQP_HVR_MATCH_NOT_FOUND;
|
||||
int i;
|
||||
int san_names_nb = -1;
|
||||
STACK_OF(GENERAL_NAME) *san_names = NULL;
|
||||
|
||||
// Try to extract the names within the SAN extension from the certificate
|
||||
san_names =
|
||||
X509_get_ext_d2i((X509 *)server_cert, NID_subject_alt_name, NULL, NULL);
|
||||
if (san_names == NULL) {
|
||||
return AMQP_HVR_NO_SAN_PRESENT;
|
||||
}
|
||||
san_names_nb = sk_GENERAL_NAME_num(san_names);
|
||||
|
||||
// Check each name within the extension
|
||||
for (i = 0; i < san_names_nb; i++) {
|
||||
const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);
|
||||
|
||||
if (current_name->type == GEN_DNS) {
|
||||
// Current name is a DNS name, let's check it
|
||||
const char *dns_name = (const char *)
|
||||
#ifdef AMQP_OPENSSL_V110
|
||||
ASN1_STRING_get0_data(current_name->d.dNSName);
|
||||
#else
|
||||
ASN1_STRING_data(current_name->d.dNSName);
|
||||
#endif
|
||||
|
||||
// Make sure there isn't an embedded NUL character in the DNS name
|
||||
if ((size_t)ASN1_STRING_length(current_name->d.dNSName) !=
|
||||
strlen(dns_name)) {
|
||||
result = AMQP_HVR_MALFORMED_CERTIFICATE;
|
||||
break;
|
||||
} else { // Compare expected hostname with the DNS name
|
||||
if (amqp_hostcheck(dns_name, hostname) == AMQP_HCR_MATCH) {
|
||||
result = AMQP_HVR_MATCH_FOUND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the server's identity by looking for the expected hostname in the
|
||||
* server's certificate. As described in RFC 6125, it first tries to find a
|
||||
* match in the Subject Alternative Name extension. If the extension is not
|
||||
* present in the certificate, it checks the Common Name instead.
|
||||
*
|
||||
* Returns AMQP_HVR_MATCH_FOUND if a match was found.
|
||||
* Returns AMQP_HVR_MATCH_NOT_FOUND if no matches were found.
|
||||
* Returns AMQP_HVR_MALFORMED_CERTIFICATE if any of the hostnames had a NUL
|
||||
* character embedded in it.
|
||||
* Returns AMQP_HVR_ERROR if there was an error.
|
||||
*/
|
||||
amqp_hostname_validation_result amqp_ssl_validate_hostname(
|
||||
const char *hostname, const X509 *server_cert) {
|
||||
amqp_hostname_validation_result result;
|
||||
|
||||
if ((hostname == NULL) || (server_cert == NULL)) return AMQP_HVR_ERROR;
|
||||
|
||||
// First try the Subject Alternative Names extension
|
||||
result = amqp_matches_subject_alternative_name(hostname, server_cert);
|
||||
if (result == AMQP_HVR_NO_SAN_PRESENT) {
|
||||
// Extension was not found: try the Common Name
|
||||
result = amqp_matches_common_name(hostname, server_cert);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
#ifndef librabbitmq_amqp_openssl_hostname_validation_h
|
||||
#define librabbitmq_amqp_openssl_hostname_validation_h
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012, iSEC Partners.
|
||||
* Copyright (C) 2015 Alan Antonuk.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of a copyright holder shall
|
||||
* not be used in advertising or otherwise to promote the sale, use or other
|
||||
* dealings in this Software without prior written authorization of the
|
||||
* copyright holder.
|
||||
*/
|
||||
|
||||
/* Originally from:
|
||||
* https://github.com/iSECPartners/ssl-conservatory
|
||||
* https://wiki.openssl.org/index.php/Hostname_validation
|
||||
*/
|
||||
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
typedef enum {
|
||||
AMQP_HVR_MATCH_FOUND,
|
||||
AMQP_HVR_MATCH_NOT_FOUND,
|
||||
AMQP_HVR_NO_SAN_PRESENT,
|
||||
AMQP_HVR_MALFORMED_CERTIFICATE,
|
||||
AMQP_HVR_ERROR
|
||||
} amqp_hostname_validation_result;
|
||||
|
||||
/**
|
||||
* Validates the server's identity by looking for the expected hostname in the
|
||||
* server's certificate. As described in RFC 6125, it first tries to find a match
|
||||
* in the Subject Alternative Name extension. If the extension is not present in
|
||||
* the certificate, it checks the Common Name instead.
|
||||
*
|
||||
* Returns AMQP_HVR_MATCH_FOUND if a match was found.
|
||||
* Returns AMQP_HVR_MATCH_NOT_FOUND if no matches were found.
|
||||
* Returns AMQP_HVR_MALFORMED_CERTIFICATE if any of the hostnames had a NUL
|
||||
* character embedded in it.
|
||||
* Returns AMQP_HVR_ERROR if there was an error.
|
||||
*/
|
||||
amqp_hostname_validation_result amqp_ssl_validate_hostname(
|
||||
const char *hostname, const X509 *server_cert);
|
||||
|
||||
#endif
|
|
@ -1,374 +0,0 @@
|
|||
#ifndef librabbitmq_amqp_private_h
|
||||
#define librabbitmq_amqp_private_h
|
||||
|
||||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2014
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define AMQ_COPYRIGHT \
|
||||
"Copyright (c) 2007-2014 VMWare Inc, Tony Garnock-Jones," \
|
||||
" and Alan Antonuk."
|
||||
|
||||
#include "amqp.h"
|
||||
#include "amqp_framing.h"
|
||||
#include <string.h>
|
||||
|
||||
#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
|
||||
#ifndef WINVER
|
||||
/* WINVER 0x0502 is WinXP SP2+, Windows Server 2003 SP1+
|
||||
* See:
|
||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa383745(v=vs.85).aspx#macros_for_conditional_declarations
|
||||
*/
|
||||
#define WINVER 0x0502
|
||||
#endif
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
/* GCC attributes */
|
||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
|
||||
#define AMQP_NORETURN __attribute__((__noreturn__))
|
||||
#define AMQP_UNUSED __attribute__((__unused__))
|
||||
#elif defined(_MSC_VER)
|
||||
#define AMQP_NORETURN __declspec(noreturn)
|
||||
#define AMQP_UNUSED
|
||||
#else
|
||||
#define AMQP_NORETURN
|
||||
#define AMQP_UNUSED
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 4
|
||||
#define AMQP_PRIVATE __attribute__((visibility("hidden")))
|
||||
#else
|
||||
#define AMQP_PRIVATE
|
||||
#endif
|
||||
|
||||
char *amqp_os_error_string(int err);
|
||||
|
||||
#ifdef WITH_SSL
|
||||
char *amqp_ssl_error_string(int err);
|
||||
#endif
|
||||
|
||||
#include "amqp_socket.h"
|
||||
#include "amqp_time.h"
|
||||
|
||||
/*
|
||||
* Connection states: XXX FIX THIS
|
||||
*
|
||||
* - CONNECTION_STATE_INITIAL: The initial state, when we cannot be
|
||||
* sure if the next thing we will get is the first AMQP frame, or a
|
||||
* protocol header from the server.
|
||||
*
|
||||
* - CONNECTION_STATE_IDLE: The normal state between
|
||||
* frames. Connections may only be reconfigured, and the
|
||||
* connection's pools recycled, when in this state. Whenever we're
|
||||
* in this state, the inbound_buffer's bytes pointer must be NULL;
|
||||
* any other state, and it must point to a block of memory allocated
|
||||
* from the frame_pool.
|
||||
*
|
||||
* - CONNECTION_STATE_HEADER: Some bytes of an incoming frame have
|
||||
* been seen, but not a complete frame header's worth.
|
||||
*
|
||||
* - CONNECTION_STATE_BODY: A complete frame header has been seen, but
|
||||
* the frame is not yet complete. When it is completed, it will be
|
||||
* returned, and the connection will return to IDLE state.
|
||||
*
|
||||
*/
|
||||
typedef enum amqp_connection_state_enum_ {
|
||||
CONNECTION_STATE_IDLE = 0,
|
||||
CONNECTION_STATE_INITIAL,
|
||||
CONNECTION_STATE_HEADER,
|
||||
CONNECTION_STATE_BODY
|
||||
} amqp_connection_state_enum;
|
||||
|
||||
typedef enum amqp_status_private_enum_ {
|
||||
/* 0x00xx -> AMQP_STATUS_*/
|
||||
/* 0x01xx -> AMQP_STATUS_TCP_* */
|
||||
/* 0x02xx -> AMQP_STATUS_SSL_* */
|
||||
AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD = -0x1301,
|
||||
AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE = -0x1302
|
||||
} amqp_status_private_enum;
|
||||
|
||||
/* 7 bytes up front, then payload, then 1 byte footer */
|
||||
#define HEADER_SIZE 7
|
||||
#define FOOTER_SIZE 1
|
||||
|
||||
#define AMQP_PSEUDOFRAME_PROTOCOL_HEADER 'A'
|
||||
|
||||
typedef struct amqp_link_t_ {
|
||||
struct amqp_link_t_ *next;
|
||||
void *data;
|
||||
} amqp_link_t;
|
||||
|
||||
#define POOL_TABLE_SIZE 16
|
||||
|
||||
typedef struct amqp_pool_table_entry_t_ {
|
||||
struct amqp_pool_table_entry_t_ *next;
|
||||
amqp_pool_t pool;
|
||||
amqp_channel_t channel;
|
||||
} amqp_pool_table_entry_t;
|
||||
|
||||
struct amqp_connection_state_t_ {
|
||||
amqp_pool_table_entry_t *pool_table[POOL_TABLE_SIZE];
|
||||
|
||||
amqp_connection_state_enum state;
|
||||
|
||||
int channel_max;
|
||||
int frame_max;
|
||||
|
||||
/* Heartbeat interval in seconds. If this is <= 0, then heartbeats are not
|
||||
* enabled, and next_recv_heartbeat and next_send_heartbeat are set to
|
||||
* infinite */
|
||||
int heartbeat;
|
||||
amqp_time_t next_recv_heartbeat;
|
||||
amqp_time_t next_send_heartbeat;
|
||||
|
||||
/* buffer for holding frame headers. Allows us to delay allocating
|
||||
* the raw frame buffer until the type, channel, and size are all known
|
||||
*/
|
||||
char header_buffer[HEADER_SIZE + 1];
|
||||
amqp_bytes_t inbound_buffer;
|
||||
|
||||
size_t inbound_offset;
|
||||
size_t target_size;
|
||||
|
||||
amqp_bytes_t outbound_buffer;
|
||||
|
||||
amqp_socket_t *socket;
|
||||
|
||||
amqp_bytes_t sock_inbound_buffer;
|
||||
size_t sock_inbound_offset;
|
||||
size_t sock_inbound_limit;
|
||||
|
||||
amqp_link_t *first_queued_frame;
|
||||
amqp_link_t *last_queued_frame;
|
||||
|
||||
amqp_rpc_reply_t most_recent_api_result;
|
||||
|
||||
amqp_table_t server_properties;
|
||||
amqp_table_t client_properties;
|
||||
amqp_pool_t properties_pool;
|
||||
|
||||
struct timeval *handshake_timeout;
|
||||
struct timeval internal_handshake_timeout;
|
||||
struct timeval *rpc_timeout;
|
||||
struct timeval internal_rpc_timeout;
|
||||
};
|
||||
|
||||
amqp_pool_t *amqp_get_or_create_channel_pool(amqp_connection_state_t connection,
|
||||
amqp_channel_t channel);
|
||||
amqp_pool_t *amqp_get_channel_pool(amqp_connection_state_t state,
|
||||
amqp_channel_t channel);
|
||||
|
||||
static inline int amqp_heartbeat_send(amqp_connection_state_t state) {
|
||||
return state->heartbeat;
|
||||
}
|
||||
|
||||
static inline int amqp_heartbeat_recv(amqp_connection_state_t state) {
|
||||
return 2 * state->heartbeat;
|
||||
}
|
||||
|
||||
int amqp_try_recv(amqp_connection_state_t state);
|
||||
|
||||
static inline void *amqp_offset(void *data, size_t offset) {
|
||||
return (char *)data + offset;
|
||||
}
|
||||
|
||||
/* This macro defines the encoding and decoding functions associated with a
|
||||
simple type. */
|
||||
|
||||
#define DECLARE_CODEC_BASE_TYPE(bits) \
|
||||
\
|
||||
static inline int amqp_encode_##bits(amqp_bytes_t encoded, size_t *offset, \
|
||||
uint##bits##_t input) { \
|
||||
size_t o = *offset; \
|
||||
if ((*offset = o + bits / 8) <= encoded.len) { \
|
||||
amqp_e##bits(input, amqp_offset(encoded.bytes, o)); \
|
||||
return 1; \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static inline int amqp_decode_##bits(amqp_bytes_t encoded, size_t *offset, \
|
||||
uint##bits##_t *output) { \
|
||||
size_t o = *offset; \
|
||||
if ((*offset = o + bits / 8) <= encoded.len) { \
|
||||
*output = amqp_d##bits(amqp_offset(encoded.bytes, o)); \
|
||||
return 1; \
|
||||
} \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
static inline int is_bigendian(void) {
|
||||
union {
|
||||
uint32_t i;
|
||||
char c[4];
|
||||
} bint = {0x01020304};
|
||||
return bint.c[0] == 1;
|
||||
}
|
||||
|
||||
static inline void amqp_e8(uint8_t val, void *data) {
|
||||
memcpy(data, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static inline uint8_t amqp_d8(void *data) {
|
||||
uint8_t val;
|
||||
memcpy(&val, data, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void amqp_e16(uint16_t val, void *data) {
|
||||
if (!is_bigendian()) {
|
||||
val = ((val & 0xFF00u) >> 8u) | ((val & 0x00FFu) << 8u);
|
||||
}
|
||||
memcpy(data, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static inline uint16_t amqp_d16(void *data) {
|
||||
uint16_t val;
|
||||
memcpy(&val, data, sizeof(val));
|
||||
if (!is_bigendian()) {
|
||||
val = ((val & 0xFF00u) >> 8u) | ((val & 0x00FFu) << 8u);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void amqp_e32(uint32_t val, void *data) {
|
||||
if (!is_bigendian()) {
|
||||
val = ((val & 0xFF000000u) >> 24u) | ((val & 0x00FF0000u) >> 8u) |
|
||||
((val & 0x0000FF00u) << 8u) | ((val & 0x000000FFu) << 24u);
|
||||
}
|
||||
memcpy(data, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static inline uint32_t amqp_d32(void *data) {
|
||||
uint32_t val;
|
||||
memcpy(&val, data, sizeof(val));
|
||||
if (!is_bigendian()) {
|
||||
val = ((val & 0xFF000000u) >> 24u) | ((val & 0x00FF0000u) >> 8u) |
|
||||
((val & 0x0000FF00u) << 8u) | ((val & 0x000000FFu) << 24u);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void amqp_e64(uint64_t val, void *data) {
|
||||
if (!is_bigendian()) {
|
||||
val = ((val & 0xFF00000000000000u) >> 56u) |
|
||||
((val & 0x00FF000000000000u) >> 40u) |
|
||||
((val & 0x0000FF0000000000u) >> 24u) |
|
||||
((val & 0x000000FF00000000u) >> 8u) |
|
||||
((val & 0x00000000FF000000u) << 8u) |
|
||||
((val & 0x0000000000FF0000u) << 24u) |
|
||||
((val & 0x000000000000FF00u) << 40u) |
|
||||
((val & 0x00000000000000FFu) << 56u);
|
||||
}
|
||||
memcpy(data, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static inline uint64_t amqp_d64(void *data) {
|
||||
uint64_t val;
|
||||
memcpy(&val, data, sizeof(val));
|
||||
if (!is_bigendian()) {
|
||||
val = ((val & 0xFF00000000000000u) >> 56u) |
|
||||
((val & 0x00FF000000000000u) >> 40u) |
|
||||
((val & 0x0000FF0000000000u) >> 24u) |
|
||||
((val & 0x000000FF00000000u) >> 8u) |
|
||||
((val & 0x00000000FF000000u) << 8u) |
|
||||
((val & 0x0000000000FF0000u) << 24u) |
|
||||
((val & 0x000000000000FF00u) << 40u) |
|
||||
((val & 0x00000000000000FFu) << 56u);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
DECLARE_CODEC_BASE_TYPE(8)
|
||||
DECLARE_CODEC_BASE_TYPE(16)
|
||||
DECLARE_CODEC_BASE_TYPE(32)
|
||||
DECLARE_CODEC_BASE_TYPE(64)
|
||||
|
||||
static inline int amqp_encode_bytes(amqp_bytes_t encoded, size_t *offset,
|
||||
amqp_bytes_t input) {
|
||||
size_t o = *offset;
|
||||
/* The memcpy below has undefined behavior if the input is NULL. It is valid
|
||||
* for a 0-length amqp_bytes_t to have .bytes == NULL. Thus we should check
|
||||
* before encoding.
|
||||
*/
|
||||
if (input.len == 0) {
|
||||
return 1;
|
||||
}
|
||||
if ((*offset = o + input.len) <= encoded.len) {
|
||||
memcpy(amqp_offset(encoded.bytes, o), input.bytes, input.len);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int amqp_decode_bytes(amqp_bytes_t encoded, size_t *offset,
|
||||
amqp_bytes_t *output, size_t len) {
|
||||
size_t o = *offset;
|
||||
if ((*offset = o + len) <= encoded.len) {
|
||||
output->bytes = amqp_offset(encoded.bytes, o);
|
||||
output->len = len;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
AMQP_NORETURN
|
||||
void amqp_abort(const char *fmt, ...);
|
||||
|
||||
int amqp_bytes_equal(amqp_bytes_t r, amqp_bytes_t l);
|
||||
|
||||
static inline amqp_rpc_reply_t amqp_rpc_reply_error(amqp_status_enum status) {
|
||||
amqp_rpc_reply_t reply;
|
||||
reply.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION;
|
||||
reply.library_error = status;
|
||||
return reply;
|
||||
}
|
||||
|
||||
int amqp_send_frame_inner(amqp_connection_state_t state,
|
||||
const amqp_frame_t *frame, int flags,
|
||||
amqp_time_t deadline);
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Michael Steinert are Copyright (c) 2012-2013 Michael
|
||||
* Steinert. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An abstract socket interface.
|
||||
*/
|
||||
|
||||
#ifndef AMQP_SOCKET_H
|
||||
#define AMQP_SOCKET_H
|
||||
|
||||
#include "amqp_private.h"
|
||||
#include "amqp_time.h"
|
||||
|
||||
AMQP_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
AMQP_SF_NONE = 0,
|
||||
AMQP_SF_MORE = 1,
|
||||
AMQP_SF_POLLIN = 2,
|
||||
AMQP_SF_POLLOUT = 4,
|
||||
AMQP_SF_POLLERR = 8
|
||||
} amqp_socket_flag_enum;
|
||||
|
||||
typedef enum { AMQP_SC_NONE = 0, AMQP_SC_FORCE = 1 } amqp_socket_close_enum;
|
||||
|
||||
int amqp_os_socket_error(void);
|
||||
|
||||
int amqp_os_socket_close(int sockfd);
|
||||
|
||||
/* Socket callbacks. */
|
||||
typedef ssize_t (*amqp_socket_send_fn)(void *, const void *, size_t, int);
|
||||
typedef ssize_t (*amqp_socket_recv_fn)(void *, void *, size_t, int);
|
||||
typedef int (*amqp_socket_open_fn)(void *, const char *, int, struct timeval *);
|
||||
typedef int (*amqp_socket_close_fn)(void *, amqp_socket_close_enum);
|
||||
typedef int (*amqp_socket_get_sockfd_fn)(void *);
|
||||
typedef void (*amqp_socket_delete_fn)(void *);
|
||||
|
||||
/** V-table for amqp_socket_t */
|
||||
struct amqp_socket_class_t {
|
||||
amqp_socket_send_fn send;
|
||||
amqp_socket_recv_fn recv;
|
||||
amqp_socket_open_fn open;
|
||||
amqp_socket_close_fn close;
|
||||
amqp_socket_get_sockfd_fn get_sockfd;
|
||||
amqp_socket_delete_fn delete;
|
||||
};
|
||||
|
||||
/** Abstract base class for amqp_socket_t */
|
||||
struct amqp_socket_t_ {
|
||||
const struct amqp_socket_class_t *klass;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set set the socket object for a connection
|
||||
*
|
||||
* This assigns a socket object to the connection, closing and deleting any
|
||||
* existing socket
|
||||
*
|
||||
* \param [in] state The connection object to add the socket to
|
||||
* \param [in] socket The socket object to assign to the connection
|
||||
*/
|
||||
void amqp_set_socket(amqp_connection_state_t state, amqp_socket_t *socket);
|
||||
|
||||
/**
|
||||
* Send a message from a socket.
|
||||
*
|
||||
* This function wraps send(2) functionality.
|
||||
*
|
||||
* This function will only return on error, or when all of the bytes in buf
|
||||
* have been sent, or when an error occurs.
|
||||
*
|
||||
* \param [in,out] self A socket object.
|
||||
* \param [in] buf A buffer to read from.
|
||||
* \param [in] len The number of bytes in \e buf.
|
||||
* \param [in]
|
||||
*
|
||||
* \return AMQP_STATUS_OK on success. amqp_status_enum value otherwise
|
||||
*/
|
||||
ssize_t amqp_socket_send(amqp_socket_t *self, const void *buf, size_t len,
|
||||
int flags);
|
||||
|
||||
ssize_t amqp_try_send(amqp_connection_state_t state, const void *buf,
|
||||
size_t len, amqp_time_t deadline, int flags);
|
||||
|
||||
/**
|
||||
* Receive a message from a socket.
|
||||
*
|
||||
* This function wraps recv(2) functionality.
|
||||
*
|
||||
* \param [in,out] self A socket object.
|
||||
* \param [out] buf A buffer to write to.
|
||||
* \param [in] len The number of bytes at \e buf.
|
||||
* \param [in] flags Receive flags, implementation specific.
|
||||
*
|
||||
* \return The number of bytes received, or < 0 on error (\ref amqp_status_enum)
|
||||
*/
|
||||
ssize_t amqp_socket_recv(amqp_socket_t *self, void *buf, size_t len, int flags);
|
||||
|
||||
/**
|
||||
* Close a socket connection and free resources.
|
||||
*
|
||||
* This function closes a socket connection and releases any resources used by
|
||||
* the object. After calling this function the specified socket should no
|
||||
* longer be referenced.
|
||||
*
|
||||
* \param [in,out] self A socket object.
|
||||
* \param [in] force, if set, just close the socket, don't attempt a TLS
|
||||
* shutdown.
|
||||
*
|
||||
* \return Zero upon success, non-zero otherwise.
|
||||
*/
|
||||
int amqp_socket_close(amqp_socket_t *self, amqp_socket_close_enum force);
|
||||
|
||||
/**
|
||||
* Destroy a socket object
|
||||
*
|
||||
* \param [in] self the socket object to delete
|
||||
*/
|
||||
void amqp_socket_delete(amqp_socket_t *self);
|
||||
|
||||
/**
|
||||
* Open a socket connection.
|
||||
*
|
||||
* This function opens a socket connection returned from amqp_tcp_socket_new()
|
||||
* or amqp_ssl_socket_new(). This function should be called after setting
|
||||
* socket options and prior to assigning the socket to an AMQP connection with
|
||||
* amqp_set_socket().
|
||||
*
|
||||
* \param [in] host Connect to this host.
|
||||
* \param [in] port Connect on this remote port.
|
||||
* \param [in] timeout Max allowed time to spent on opening. If NULL - run in
|
||||
* blocking mode
|
||||
*
|
||||
* \return File descriptor upon success, non-zero negative error code otherwise.
|
||||
*/
|
||||
int amqp_open_socket_noblock(char const *hostname, int portnumber,
|
||||
struct timeval *timeout);
|
||||
|
||||
int amqp_open_socket_inner(char const *hostname, int portnumber,
|
||||
amqp_time_t deadline);
|
||||
|
||||
/* Wait up to dealline for fd to become readable or writeable depending on
|
||||
* event (AMQP_SF_POLLIN, AMQP_SF_POLLOUT) */
|
||||
int amqp_poll(int fd, int event, amqp_time_t deadline);
|
||||
|
||||
int amqp_send_method_inner(amqp_connection_state_t state,
|
||||
amqp_channel_t channel, amqp_method_number_t id,
|
||||
void *decoded, int flags, amqp_time_t deadline);
|
||||
|
||||
int amqp_queue_frame(amqp_connection_state_t state, amqp_frame_t *frame);
|
||||
|
||||
int amqp_put_back_frame(amqp_connection_state_t state, amqp_frame_t *frame);
|
||||
|
||||
int amqp_simple_wait_frame_on_channel(amqp_connection_state_t state,
|
||||
amqp_channel_t channel,
|
||||
amqp_frame_t *decoded_frame);
|
||||
|
||||
int sasl_mechanism_in_list(amqp_bytes_t mechanisms,
|
||||
amqp_sasl_method_enum method);
|
||||
|
||||
int amqp_merge_capabilities(const amqp_table_t *base, const amqp_table_t *add,
|
||||
amqp_table_t *result, amqp_pool_t *pool);
|
||||
AMQP_END_DECLS
|
||||
|
||||
#endif /* AMQP_SOCKET_H */
|
|
@ -1,239 +0,0 @@
|
|||
/** \file */
|
||||
/*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Michael Steinert are Copyright (c) 2012-2013 Michael
|
||||
* Steinert. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef AMQP_SSL_H
|
||||
#define AMQP_SSL_H
|
||||
|
||||
#include <amqp.h>
|
||||
|
||||
AMQP_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* Create a new SSL/TLS socket object.
|
||||
*
|
||||
* The returned socket object is owned by the \ref amqp_connection_state_t
|
||||
* object and will be destroyed when the state object is destroyed or a new
|
||||
* socket object is created.
|
||||
*
|
||||
* If the socket object creation fails, the \ref amqp_connection_state_t object
|
||||
* will not be changed.
|
||||
*
|
||||
* The object returned by this function can be retrieved from the
|
||||
* amqp_connection_state_t object later using the amqp_get_socket() function.
|
||||
*
|
||||
* Calling this function may result in the underlying SSL library being
|
||||
* initialized.
|
||||
* \sa amqp_set_initialize_ssl_library()
|
||||
*
|
||||
* \param [in,out] state The connection object that owns the SSL/TLS socket
|
||||
* \return A new socket object or NULL if an error occurred.
|
||||
*
|
||||
* \since v0.4.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
amqp_socket_t *AMQP_CALL amqp_ssl_socket_new(amqp_connection_state_t state);
|
||||
|
||||
/**
|
||||
* Set the CA certificate.
|
||||
*
|
||||
* \param [in,out] self An SSL/TLS socket object.
|
||||
* \param [in] cacert Path to the CA cert file in PEM format.
|
||||
*
|
||||
* \return \ref AMQP_STATUS_OK on success an \ref amqp_status_enum value on
|
||||
* failure.
|
||||
*
|
||||
* \since v0.4.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
int AMQP_CALL amqp_ssl_socket_set_cacert(amqp_socket_t *self,
|
||||
const char *cacert);
|
||||
|
||||
/**
|
||||
* Set the client key.
|
||||
*
|
||||
* \param [in,out] self An SSL/TLS socket object.
|
||||
* \param [in] cert Path to the client certificate in PEM foramt.
|
||||
* \param [in] key Path to the client key in PEM format.
|
||||
*
|
||||
* \return \ref AMQP_STATUS_OK on success an \ref amqp_status_enum value on
|
||||
* failure.
|
||||
*
|
||||
* \since v0.4.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
int AMQP_CALL amqp_ssl_socket_set_key(amqp_socket_t *self, const char *cert,
|
||||
const char *key);
|
||||
|
||||
/**
|
||||
* Set the client key from a buffer.
|
||||
*
|
||||
* \param [in,out] self An SSL/TLS socket object.
|
||||
* \param [in] cert Path to the client certificate in PEM foramt.
|
||||
* \param [in] key A buffer containing client key in PEM format.
|
||||
* \param [in] n The length of the buffer.
|
||||
*
|
||||
* \return \ref AMQP_STATUS_OK on success an \ref amqp_status_enum value on
|
||||
* failure.
|
||||
*
|
||||
* \since v0.4.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
int AMQP_CALL amqp_ssl_socket_set_key_buffer(amqp_socket_t *self,
|
||||
const char *cert, const void *key,
|
||||
size_t n);
|
||||
|
||||
/**
|
||||
* Enable or disable peer verification.
|
||||
*
|
||||
* \deprecated use \amqp_ssl_socket_set_verify_peer and
|
||||
* \amqp_ssl_socket_set_verify_hostname instead.
|
||||
*
|
||||
* If peer verification is enabled then the common name in the server
|
||||
* certificate must match the server name. Peer verification is enabled by
|
||||
* default.
|
||||
*
|
||||
* \param [in,out] self An SSL/TLS socket object.
|
||||
* \param [in] verify Enable or disable peer verification.
|
||||
*
|
||||
* \since v0.4.0
|
||||
*/
|
||||
AMQP_DEPRECATED(AMQP_PUBLIC_FUNCTION void AMQP_CALL amqp_ssl_socket_set_verify(
|
||||
amqp_socket_t *self, amqp_boolean_t verify));
|
||||
|
||||
/**
|
||||
* Enable or disable peer verification.
|
||||
*
|
||||
* Peer verification validates the certificate chain that is sent by the broker.
|
||||
* Hostname validation is controlled by \amqp_ssl_socket_set_verify_peer.
|
||||
*
|
||||
* \param [in,out] self An SSL/TLS socket object.
|
||||
* \param [in] verify enable or disable peer validation
|
||||
*
|
||||
* \since v0.8.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
void AMQP_CALL amqp_ssl_socket_set_verify_peer(amqp_socket_t *self,
|
||||
amqp_boolean_t verify);
|
||||
|
||||
/**
|
||||
* Enable or disable hostname verification.
|
||||
*
|
||||
* Hostname verification checks the broker cert for a CN or SAN that matches the
|
||||
* hostname that amqp_socket_open() is presented. Peer verification is
|
||||
* controlled by \amqp_ssl_socket_set_verify_peer
|
||||
*
|
||||
* \since v0.8.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
void AMQP_CALL amqp_ssl_socket_set_verify_hostname(amqp_socket_t *self,
|
||||
amqp_boolean_t verify);
|
||||
|
||||
typedef enum {
|
||||
AMQP_TLSv1 = 1,
|
||||
AMQP_TLSv1_1 = 2,
|
||||
AMQP_TLSv1_2 = 3,
|
||||
AMQP_TLSvLATEST = 0xFFFF
|
||||
} amqp_tls_version_t;
|
||||
|
||||
/**
|
||||
* Set min and max TLS versions.
|
||||
*
|
||||
* Set the oldest and newest acceptable TLS versions that are acceptable when
|
||||
* connecting to the broker. Set min == max to restrict to just that
|
||||
* version.
|
||||
*
|
||||
* \param [in,out] self An SSL/TLS socket object.
|
||||
* \param [in] min the minimum acceptable TLS version
|
||||
* \param [in] max the maxmium acceptable TLS version
|
||||
* \returns AMQP_STATUS_OK on success, AMQP_STATUS_UNSUPPORTED if OpenSSL does
|
||||
* not support the requested TLS version, AMQP_STATUS_INVALID_PARAMETER if an
|
||||
* invalid combination of parameters is passed.
|
||||
*
|
||||
* \since v0.8.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
int AMQP_CALL amqp_ssl_socket_set_ssl_versions(amqp_socket_t *self,
|
||||
amqp_tls_version_t min,
|
||||
amqp_tls_version_t max);
|
||||
|
||||
/**
|
||||
* Sets whether rabbitmq-c will initialize OpenSSL.
|
||||
*
|
||||
* OpenSSL requires a one-time initialization across a whole program, this sets
|
||||
* whether or not rabbitmq-c will initialize the SSL library when the first call
|
||||
* to amqp_ssl_socket_new() is made. You should call this function with
|
||||
* do_init = 0 if the underlying SSL library is initialized somewhere else
|
||||
* the program.
|
||||
*
|
||||
* Failing to initialize or double initialization of the SSL library will
|
||||
* result in undefined behavior
|
||||
*
|
||||
* By default rabbitmq-c will initialize the underlying SSL library.
|
||||
*
|
||||
* NOTE: calling this function after the first socket has been opened with
|
||||
* amqp_open_socket() will not have any effect.
|
||||
*
|
||||
* \param [in] do_initialize If 0 rabbitmq-c will not initialize the SSL
|
||||
* library, otherwise rabbitmq-c will initialize the
|
||||
* SSL library
|
||||
*
|
||||
* \since v0.4.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
void AMQP_CALL amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize);
|
||||
|
||||
/**
|
||||
* Initialize the underlying SSL/TLS library.
|
||||
*
|
||||
* The OpenSSL library requires a one-time initialization across the whole
|
||||
* program.
|
||||
*
|
||||
* This function unconditionally initializes OpenSSL so that rabbitmq-c may
|
||||
* use it.
|
||||
*
|
||||
* This function is thread-safe, and may be called more than once.
|
||||
*
|
||||
* \return AMQP_STATUS_OK on success.
|
||||
*
|
||||
* \since v0.9.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
int AMQP_CALL amqp_initialize_ssl_library(void);
|
||||
|
||||
/**
|
||||
* Uninitialize the underlying SSL/TLS library.
|
||||
*
|
||||
* \return AMQP_STATUS_OK on success.
|
||||
*
|
||||
* \since v0.9.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
int AMQP_CALL amqp_uninitialize_ssl_library(void);
|
||||
|
||||
AMQP_END_DECLS
|
||||
|
||||
#endif /* AMQP_SSL_H */
|
|
@ -1,668 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "amqp_private.h"
|
||||
#include "amqp_table.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define INITIAL_ARRAY_SIZE 16
|
||||
#define INITIAL_TABLE_SIZE 16
|
||||
|
||||
static int amqp_decode_field_value(amqp_bytes_t encoded, amqp_pool_t *pool,
|
||||
amqp_field_value_t *entry, size_t *offset);
|
||||
|
||||
static int amqp_encode_field_value(amqp_bytes_t encoded,
|
||||
amqp_field_value_t *entry, size_t *offset);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static int amqp_decode_array(amqp_bytes_t encoded, amqp_pool_t *pool,
|
||||
amqp_array_t *output, size_t *offset) {
|
||||
uint32_t arraysize;
|
||||
int num_entries = 0;
|
||||
int allocated_entries = INITIAL_ARRAY_SIZE;
|
||||
amqp_field_value_t *entries;
|
||||
size_t limit;
|
||||
int res;
|
||||
|
||||
if (!amqp_decode_32(encoded, offset, &arraysize)) {
|
||||
return AMQP_STATUS_BAD_AMQP_DATA;
|
||||
}
|
||||
|
||||
if (arraysize + *offset > encoded.len) {
|
||||
return AMQP_STATUS_BAD_AMQP_DATA;
|
||||
}
|
||||
|
||||
entries = malloc(allocated_entries * sizeof(amqp_field_value_t));
|
||||
if (entries == NULL) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
limit = *offset + arraysize;
|
||||
while (*offset < limit) {
|
||||
if (num_entries >= allocated_entries) {
|
||||
void *newentries;
|
||||
allocated_entries = allocated_entries * 2;
|
||||
newentries =
|
||||
realloc(entries, allocated_entries * sizeof(amqp_field_value_t));
|
||||
res = AMQP_STATUS_NO_MEMORY;
|
||||
if (newentries == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
entries = newentries;
|
||||
}
|
||||
|
||||
res = amqp_decode_field_value(encoded, pool, &entries[num_entries], offset);
|
||||
if (res < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
num_entries++;
|
||||
}
|
||||
|
||||
output->num_entries = num_entries;
|
||||
output->entries =
|
||||
amqp_pool_alloc(pool, num_entries * sizeof(amqp_field_value_t));
|
||||
/* NULL is legitimate if we requested a zero-length block. */
|
||||
if (output->entries == NULL) {
|
||||
if (num_entries == 0) {
|
||||
res = AMQP_STATUS_OK;
|
||||
} else {
|
||||
res = AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(output->entries, entries, num_entries * sizeof(amqp_field_value_t));
|
||||
res = AMQP_STATUS_OK;
|
||||
|
||||
out:
|
||||
free(entries);
|
||||
return res;
|
||||
}
|
||||
|
||||
int amqp_decode_table(amqp_bytes_t encoded, amqp_pool_t *pool,
|
||||
amqp_table_t *output, size_t *offset) {
|
||||
uint32_t tablesize;
|
||||
int num_entries = 0;
|
||||
amqp_table_entry_t *entries;
|
||||
int allocated_entries = INITIAL_TABLE_SIZE;
|
||||
size_t limit;
|
||||
int res;
|
||||
|
||||
if (!amqp_decode_32(encoded, offset, &tablesize)) {
|
||||
return AMQP_STATUS_BAD_AMQP_DATA;
|
||||
}
|
||||
|
||||
if (tablesize + *offset > encoded.len) {
|
||||
return AMQP_STATUS_BAD_AMQP_DATA;
|
||||
}
|
||||
|
||||
entries = malloc(allocated_entries * sizeof(amqp_table_entry_t));
|
||||
if (entries == NULL) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
limit = *offset + tablesize;
|
||||
while (*offset < limit) {
|
||||
uint8_t keylen;
|
||||
|
||||
res = AMQP_STATUS_BAD_AMQP_DATA;
|
||||
if (!amqp_decode_8(encoded, offset, &keylen)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (num_entries >= allocated_entries) {
|
||||
void *newentries;
|
||||
allocated_entries = allocated_entries * 2;
|
||||
newentries =
|
||||
realloc(entries, allocated_entries * sizeof(amqp_table_entry_t));
|
||||
res = AMQP_STATUS_NO_MEMORY;
|
||||
if (newentries == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
entries = newentries;
|
||||
}
|
||||
|
||||
res = AMQP_STATUS_BAD_AMQP_DATA;
|
||||
if (!amqp_decode_bytes(encoded, offset, &entries[num_entries].key,
|
||||
keylen)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = amqp_decode_field_value(encoded, pool, &entries[num_entries].value,
|
||||
offset);
|
||||
if (res < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
num_entries++;
|
||||
}
|
||||
|
||||
output->num_entries = num_entries;
|
||||
output->entries =
|
||||
amqp_pool_alloc(pool, num_entries * sizeof(amqp_table_entry_t));
|
||||
/* NULL is legitimate if we requested a zero-length block. */
|
||||
if (output->entries == NULL) {
|
||||
if (num_entries == 0) {
|
||||
res = AMQP_STATUS_OK;
|
||||
} else {
|
||||
res = AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(output->entries, entries, num_entries * sizeof(amqp_table_entry_t));
|
||||
res = AMQP_STATUS_OK;
|
||||
|
||||
out:
|
||||
free(entries);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int amqp_decode_field_value(amqp_bytes_t encoded, amqp_pool_t *pool,
|
||||
amqp_field_value_t *entry, size_t *offset) {
|
||||
int res = AMQP_STATUS_BAD_AMQP_DATA;
|
||||
|
||||
if (!amqp_decode_8(encoded, offset, &entry->kind)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define TRIVIAL_FIELD_DECODER(bits) \
|
||||
if (!amqp_decode_##bits(encoded, offset, &entry->value.u##bits)) goto out; \
|
||||
break
|
||||
#define SIMPLE_FIELD_DECODER(bits, dest, how) \
|
||||
{ \
|
||||
uint##bits##_t val; \
|
||||
if (!amqp_decode_##bits(encoded, offset, &val)) goto out; \
|
||||
entry->value.dest = how; \
|
||||
} \
|
||||
break
|
||||
|
||||
switch (entry->kind) {
|
||||
case AMQP_FIELD_KIND_BOOLEAN:
|
||||
SIMPLE_FIELD_DECODER(8, boolean, val ? 1 : 0);
|
||||
|
||||
case AMQP_FIELD_KIND_I8:
|
||||
SIMPLE_FIELD_DECODER(8, i8, (int8_t)val);
|
||||
case AMQP_FIELD_KIND_U8:
|
||||
TRIVIAL_FIELD_DECODER(8);
|
||||
|
||||
case AMQP_FIELD_KIND_I16:
|
||||
SIMPLE_FIELD_DECODER(16, i16, (int16_t)val);
|
||||
case AMQP_FIELD_KIND_U16:
|
||||
TRIVIAL_FIELD_DECODER(16);
|
||||
|
||||
case AMQP_FIELD_KIND_I32:
|
||||
SIMPLE_FIELD_DECODER(32, i32, (int32_t)val);
|
||||
case AMQP_FIELD_KIND_U32:
|
||||
TRIVIAL_FIELD_DECODER(32);
|
||||
|
||||
case AMQP_FIELD_KIND_I64:
|
||||
SIMPLE_FIELD_DECODER(64, i64, (int64_t)val);
|
||||
case AMQP_FIELD_KIND_U64:
|
||||
TRIVIAL_FIELD_DECODER(64);
|
||||
|
||||
case AMQP_FIELD_KIND_F32:
|
||||
TRIVIAL_FIELD_DECODER(32);
|
||||
/* and by punning, f32 magically gets the right value...! */
|
||||
|
||||
case AMQP_FIELD_KIND_F64:
|
||||
TRIVIAL_FIELD_DECODER(64);
|
||||
/* and by punning, f64 magically gets the right value...! */
|
||||
|
||||
case AMQP_FIELD_KIND_DECIMAL:
|
||||
if (!amqp_decode_8(encoded, offset, &entry->value.decimal.decimals) ||
|
||||
!amqp_decode_32(encoded, offset, &entry->value.decimal.value)) {
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_UTF8:
|
||||
/* AMQP_FIELD_KIND_UTF8 and AMQP_FIELD_KIND_BYTES have the
|
||||
same implementation, but different interpretations. */
|
||||
/* fall through */
|
||||
case AMQP_FIELD_KIND_BYTES: {
|
||||
uint32_t len;
|
||||
if (!amqp_decode_32(encoded, offset, &len) ||
|
||||
!amqp_decode_bytes(encoded, offset, &entry->value.bytes, len)) {
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AMQP_FIELD_KIND_ARRAY:
|
||||
res = amqp_decode_array(encoded, pool, &(entry->value.array), offset);
|
||||
goto out;
|
||||
|
||||
case AMQP_FIELD_KIND_TIMESTAMP:
|
||||
TRIVIAL_FIELD_DECODER(64);
|
||||
|
||||
case AMQP_FIELD_KIND_TABLE:
|
||||
res = amqp_decode_table(encoded, pool, &(entry->value.table), offset);
|
||||
goto out;
|
||||
|
||||
case AMQP_FIELD_KIND_VOID:
|
||||
break;
|
||||
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = AMQP_STATUS_OK;
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static int amqp_encode_array(amqp_bytes_t encoded, amqp_array_t *input,
|
||||
size_t *offset) {
|
||||
size_t start = *offset;
|
||||
int i, res;
|
||||
|
||||
*offset += 4; /* size of the array gets filled in later on */
|
||||
|
||||
for (i = 0; i < input->num_entries; i++) {
|
||||
res = amqp_encode_field_value(encoded, &input->entries[i], offset);
|
||||
if (res < 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!amqp_encode_32(encoded, &start, (uint32_t)(*offset - start - 4))) {
|
||||
res = AMQP_STATUS_TABLE_TOO_BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = AMQP_STATUS_OK;
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
int amqp_encode_table(amqp_bytes_t encoded, amqp_table_t *input,
|
||||
size_t *offset) {
|
||||
size_t start = *offset;
|
||||
int i, res;
|
||||
|
||||
*offset += 4; /* size of the table gets filled in later on */
|
||||
|
||||
for (i = 0; i < input->num_entries; i++) {
|
||||
if (!amqp_encode_8(encoded, offset, (uint8_t)input->entries[i].key.len)) {
|
||||
res = AMQP_STATUS_TABLE_TOO_BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!amqp_encode_bytes(encoded, offset, input->entries[i].key)) {
|
||||
res = AMQP_STATUS_TABLE_TOO_BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = amqp_encode_field_value(encoded, &input->entries[i].value, offset);
|
||||
if (res < 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!amqp_encode_32(encoded, &start, (uint32_t)(*offset - start - 4))) {
|
||||
res = AMQP_STATUS_TABLE_TOO_BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = AMQP_STATUS_OK;
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int amqp_encode_field_value(amqp_bytes_t encoded,
|
||||
amqp_field_value_t *entry, size_t *offset) {
|
||||
int res = AMQP_STATUS_BAD_AMQP_DATA;
|
||||
|
||||
if (!amqp_encode_8(encoded, offset, entry->kind)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define FIELD_ENCODER(bits, val) \
|
||||
if (!amqp_encode_##bits(encoded, offset, val)) { \
|
||||
res = AMQP_STATUS_TABLE_TOO_BIG; \
|
||||
goto out; \
|
||||
} \
|
||||
break
|
||||
|
||||
switch (entry->kind) {
|
||||
case AMQP_FIELD_KIND_BOOLEAN:
|
||||
FIELD_ENCODER(8, entry->value.boolean ? 1 : 0);
|
||||
|
||||
case AMQP_FIELD_KIND_I8:
|
||||
FIELD_ENCODER(8, entry->value.i8);
|
||||
case AMQP_FIELD_KIND_U8:
|
||||
FIELD_ENCODER(8, entry->value.u8);
|
||||
|
||||
case AMQP_FIELD_KIND_I16:
|
||||
FIELD_ENCODER(16, entry->value.i16);
|
||||
case AMQP_FIELD_KIND_U16:
|
||||
FIELD_ENCODER(16, entry->value.u16);
|
||||
|
||||
case AMQP_FIELD_KIND_I32:
|
||||
FIELD_ENCODER(32, entry->value.i32);
|
||||
case AMQP_FIELD_KIND_U32:
|
||||
FIELD_ENCODER(32, entry->value.u32);
|
||||
|
||||
case AMQP_FIELD_KIND_I64:
|
||||
FIELD_ENCODER(64, entry->value.i64);
|
||||
case AMQP_FIELD_KIND_U64:
|
||||
FIELD_ENCODER(64, entry->value.u64);
|
||||
|
||||
case AMQP_FIELD_KIND_F32:
|
||||
/* by punning, u32 magically gets the right value...! */
|
||||
FIELD_ENCODER(32, entry->value.u32);
|
||||
|
||||
case AMQP_FIELD_KIND_F64:
|
||||
/* by punning, u64 magically gets the right value...! */
|
||||
FIELD_ENCODER(64, entry->value.u64);
|
||||
|
||||
case AMQP_FIELD_KIND_DECIMAL:
|
||||
if (!amqp_encode_8(encoded, offset, entry->value.decimal.decimals) ||
|
||||
!amqp_encode_32(encoded, offset, entry->value.decimal.value)) {
|
||||
res = AMQP_STATUS_TABLE_TOO_BIG;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_UTF8:
|
||||
/* AMQP_FIELD_KIND_UTF8 and AMQP_FIELD_KIND_BYTES have the
|
||||
same implementation, but different interpretations. */
|
||||
/* fall through */
|
||||
case AMQP_FIELD_KIND_BYTES:
|
||||
if (!amqp_encode_32(encoded, offset, (uint32_t)entry->value.bytes.len) ||
|
||||
!amqp_encode_bytes(encoded, offset, entry->value.bytes)) {
|
||||
res = AMQP_STATUS_TABLE_TOO_BIG;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_ARRAY:
|
||||
res = amqp_encode_array(encoded, &entry->value.array, offset);
|
||||
goto out;
|
||||
|
||||
case AMQP_FIELD_KIND_TIMESTAMP:
|
||||
FIELD_ENCODER(64, entry->value.u64);
|
||||
|
||||
case AMQP_FIELD_KIND_TABLE:
|
||||
res = amqp_encode_table(encoded, &entry->value.table, offset);
|
||||
goto out;
|
||||
|
||||
case AMQP_FIELD_KIND_VOID:
|
||||
break;
|
||||
|
||||
default:
|
||||
res = AMQP_STATUS_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = AMQP_STATUS_OK;
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
int amqp_table_entry_cmp(void const *entry1, void const *entry2) {
|
||||
amqp_table_entry_t const *p1 = (amqp_table_entry_t const *)entry1;
|
||||
amqp_table_entry_t const *p2 = (amqp_table_entry_t const *)entry2;
|
||||
|
||||
int d;
|
||||
size_t minlen;
|
||||
|
||||
minlen = p1->key.len;
|
||||
if (p2->key.len < minlen) {
|
||||
minlen = p2->key.len;
|
||||
}
|
||||
|
||||
d = memcmp(p1->key.bytes, p2->key.bytes, minlen);
|
||||
if (d != 0) {
|
||||
return d;
|
||||
}
|
||||
|
||||
return (int)p1->key.len - (int)p2->key.len;
|
||||
}
|
||||
|
||||
static int amqp_field_value_clone(const amqp_field_value_t *original,
|
||||
amqp_field_value_t *clone,
|
||||
amqp_pool_t *pool) {
|
||||
int i;
|
||||
int res;
|
||||
clone->kind = original->kind;
|
||||
|
||||
switch (clone->kind) {
|
||||
case AMQP_FIELD_KIND_BOOLEAN:
|
||||
clone->value.boolean = original->value.boolean;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_I8:
|
||||
clone->value.i8 = original->value.i8;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_U8:
|
||||
clone->value.u8 = original->value.u8;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_I16:
|
||||
clone->value.i16 = original->value.i16;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_U16:
|
||||
clone->value.u16 = original->value.u16;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_I32:
|
||||
clone->value.i32 = original->value.i32;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_U32:
|
||||
clone->value.u32 = original->value.u32;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_I64:
|
||||
clone->value.i64 = original->value.i64;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_U64:
|
||||
case AMQP_FIELD_KIND_TIMESTAMP:
|
||||
clone->value.u64 = original->value.u64;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_F32:
|
||||
clone->value.f32 = original->value.f32;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_F64:
|
||||
clone->value.f64 = original->value.f64;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_DECIMAL:
|
||||
clone->value.decimal = original->value.decimal;
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_UTF8:
|
||||
case AMQP_FIELD_KIND_BYTES:
|
||||
if (0 == original->value.bytes.len) {
|
||||
clone->value.bytes = amqp_empty_bytes;
|
||||
} else {
|
||||
amqp_pool_alloc_bytes(pool, original->value.bytes.len,
|
||||
&clone->value.bytes);
|
||||
if (NULL == clone->value.bytes.bytes) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
memcpy(clone->value.bytes.bytes, original->value.bytes.bytes,
|
||||
clone->value.bytes.len);
|
||||
}
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_ARRAY:
|
||||
if (0 == original->value.array.entries) {
|
||||
clone->value.array = amqp_empty_array;
|
||||
} else {
|
||||
clone->value.array.num_entries = original->value.array.num_entries;
|
||||
clone->value.array.entries = amqp_pool_alloc(
|
||||
pool, clone->value.array.num_entries * sizeof(amqp_field_value_t));
|
||||
if (NULL == clone->value.array.entries) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (i = 0; i < clone->value.array.num_entries; ++i) {
|
||||
res = amqp_field_value_clone(&original->value.array.entries[i],
|
||||
&clone->value.array.entries[i], pool);
|
||||
if (AMQP_STATUS_OK != res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AMQP_FIELD_KIND_TABLE:
|
||||
return amqp_table_clone(&original->value.table, &clone->value.table,
|
||||
pool);
|
||||
|
||||
case AMQP_FIELD_KIND_VOID:
|
||||
break;
|
||||
|
||||
default:
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
static int amqp_table_entry_clone(const amqp_table_entry_t *original,
|
||||
amqp_table_entry_t *clone,
|
||||
amqp_pool_t *pool) {
|
||||
if (0 == original->key.len) {
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
amqp_pool_alloc_bytes(pool, original->key.len, &clone->key);
|
||||
if (NULL == clone->key.bytes) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(clone->key.bytes, original->key.bytes, clone->key.len);
|
||||
|
||||
return amqp_field_value_clone(&original->value, &clone->value, pool);
|
||||
}
|
||||
|
||||
int amqp_table_clone(const amqp_table_t *original, amqp_table_t *clone,
|
||||
amqp_pool_t *pool) {
|
||||
int i;
|
||||
int res;
|
||||
clone->num_entries = original->num_entries;
|
||||
if (0 == clone->num_entries) {
|
||||
*clone = amqp_empty_table;
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
clone->entries =
|
||||
amqp_pool_alloc(pool, clone->num_entries * sizeof(amqp_table_entry_t));
|
||||
|
||||
if (NULL == clone->entries) {
|
||||
return AMQP_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (i = 0; i < clone->num_entries; ++i) {
|
||||
res =
|
||||
amqp_table_entry_clone(&original->entries[i], &clone->entries[i], pool);
|
||||
if (AMQP_STATUS_OK != res) {
|
||||
goto error_out1;
|
||||
}
|
||||
}
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
|
||||
error_out1:
|
||||
return res;
|
||||
}
|
||||
|
||||
amqp_table_entry_t amqp_table_construct_utf8_entry(const char *key,
|
||||
const char *value) {
|
||||
amqp_table_entry_t ret;
|
||||
ret.key = amqp_cstring_bytes(key);
|
||||
ret.value.kind = AMQP_FIELD_KIND_UTF8;
|
||||
ret.value.value.bytes = amqp_cstring_bytes(value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
amqp_table_entry_t amqp_table_construct_table_entry(const char *key,
|
||||
const amqp_table_t *value) {
|
||||
amqp_table_entry_t ret;
|
||||
ret.key = amqp_cstring_bytes(key);
|
||||
ret.value.kind = AMQP_FIELD_KIND_TABLE;
|
||||
ret.value.value.table = *value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
amqp_table_entry_t amqp_table_construct_bool_entry(const char *key,
|
||||
const int value) {
|
||||
amqp_table_entry_t ret;
|
||||
ret.key = amqp_cstring_bytes(key);
|
||||
ret.value.kind = AMQP_FIELD_KIND_BOOLEAN;
|
||||
ret.value.value.boolean = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
amqp_table_entry_t *amqp_table_get_entry_by_key(const amqp_table_t *table,
|
||||
const amqp_bytes_t key) {
|
||||
int i;
|
||||
assert(table != NULL);
|
||||
for (i = 0; i < table->num_entries; ++i) {
|
||||
if (amqp_bytes_equal(table->entries[i].key, key)) {
|
||||
return &table->entries[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2014 Alan Antonuk.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
#ifndef AMQP_TABLE_H
|
||||
#define AMQP_TABLE_H
|
||||
|
||||
#include "amqp.h"
|
||||
#include "amqp_private.h"
|
||||
|
||||
/**
|
||||
* Initializes a table entry with utf-8 string type value.
|
||||
*
|
||||
* \param [in] key the table entry key. The string must remain valid for the
|
||||
* life of the resulting amqp_table_entry_t.
|
||||
* \param [in] value the string value. The string must remain valid for the life
|
||||
* of the resulting amqp_table_entry_t.
|
||||
* \returns An initialized table entry.
|
||||
*/
|
||||
amqp_table_entry_t amqp_table_construct_utf8_entry(const char *key,
|
||||
const char *value);
|
||||
|
||||
/**
|
||||
* Initializes a table entry with table type value.
|
||||
*
|
||||
* \param [in] key the table entry key. The string must remain value for the
|
||||
* life of the resulting amqp_table_entry_t.
|
||||
* \param [in] value the amqp_table_t value. The table must remain valid for the
|
||||
* life of the resulting amqp_table_entry_t.
|
||||
* \returns An initialized table entry.
|
||||
*/
|
||||
amqp_table_entry_t amqp_table_construct_table_entry(const char *key,
|
||||
const amqp_table_t *value);
|
||||
|
||||
/**
|
||||
* Initializes a table entry with boolean type value.
|
||||
*
|
||||
* \param [in] key the table entry key. The string must remain value for the
|
||||
* life of the resulting amqp_table_entry_t.
|
||||
* \param [in] value the boolean value. 0 means false, any other value is true.
|
||||
* \returns An initialized table entry.
|
||||
*/
|
||||
amqp_table_entry_t amqp_table_construct_bool_entry(const char *key,
|
||||
const int value);
|
||||
|
||||
/**
|
||||
* Searches a table for an entry with a matching key.
|
||||
*
|
||||
* \param [in] table the table to search.
|
||||
* \param [in] key the string to search with.
|
||||
* \returns a pointer to the table entry in the table if a matching key can be
|
||||
* found, NULL otherwise.
|
||||
*/
|
||||
amqp_table_entry_t *amqp_table_get_entry_by_key(const amqp_table_t *table,
|
||||
const amqp_bytes_t key);
|
||||
|
||||
#endif /* AMQP_TABLE_H */
|
|
@ -1,238 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2013 Michael Steinert
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "amqp_private.h"
|
||||
#include "amqp_tcp_socket.h"
|
||||
|
||||
#include <errno.h>
|
||||
#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct amqp_tcp_socket_t {
|
||||
const struct amqp_socket_class_t *klass;
|
||||
int sockfd;
|
||||
int internal_error;
|
||||
int state;
|
||||
};
|
||||
|
||||
static ssize_t amqp_tcp_socket_send(void *base, const void *buf, size_t len,
|
||||
int flags) {
|
||||
struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
|
||||
ssize_t res;
|
||||
int flagz = 0;
|
||||
|
||||
if (-1 == self->sockfd) {
|
||||
return AMQP_STATUS_SOCKET_CLOSED;
|
||||
}
|
||||
|
||||
#ifdef MSG_NOSIGNAL
|
||||
flagz |= MSG_NOSIGNAL;
|
||||
#endif
|
||||
|
||||
#if defined(MSG_MORE)
|
||||
if (flags & AMQP_SF_MORE) {
|
||||
flagz |= MSG_MORE;
|
||||
}
|
||||
/* Cygwin defines TCP_NOPUSH, but trying to use it will return not
|
||||
* implemented. Disable it here. */
|
||||
#elif defined(TCP_NOPUSH) && !defined(__CYGWIN__)
|
||||
if (flags & AMQP_SF_MORE && !(self->state & AMQP_SF_MORE)) {
|
||||
int one = 1;
|
||||
res = setsockopt(self->sockfd, IPPROTO_TCP, TCP_NOPUSH, &one, sizeof(one));
|
||||
if (0 != res) {
|
||||
self->internal_error = res;
|
||||
return AMQP_STATUS_SOCKET_ERROR;
|
||||
}
|
||||
self->state |= AMQP_SF_MORE;
|
||||
} else if (!(flags & AMQP_SF_MORE) && self->state & AMQP_SF_MORE) {
|
||||
int zero = 0;
|
||||
res =
|
||||
setsockopt(self->sockfd, IPPROTO_TCP, TCP_NOPUSH, &zero, sizeof(&zero));
|
||||
if (0 != res) {
|
||||
self->internal_error = res;
|
||||
res = AMQP_STATUS_SOCKET_ERROR;
|
||||
} else {
|
||||
self->state &= ~AMQP_SF_MORE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
start:
|
||||
#ifdef _WIN32
|
||||
res = send(self->sockfd, buf, (int)len, flagz);
|
||||
#else
|
||||
res = send(self->sockfd, buf, len, flagz);
|
||||
#endif
|
||||
|
||||
if (res < 0) {
|
||||
self->internal_error = amqp_os_socket_error();
|
||||
switch (self->internal_error) {
|
||||
case EINTR:
|
||||
goto start;
|
||||
#ifdef _WIN32
|
||||
case WSAEWOULDBLOCK:
|
||||
#else
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
|
||||
case EAGAIN:
|
||||
#endif
|
||||
res = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE;
|
||||
break;
|
||||
default:
|
||||
res = AMQP_STATUS_SOCKET_ERROR;
|
||||
}
|
||||
} else {
|
||||
self->internal_error = 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t amqp_tcp_socket_recv(void *base, void *buf, size_t len,
|
||||
int flags) {
|
||||
struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
|
||||
ssize_t ret;
|
||||
if (-1 == self->sockfd) {
|
||||
return AMQP_STATUS_SOCKET_CLOSED;
|
||||
}
|
||||
|
||||
start:
|
||||
#ifdef _WIN32
|
||||
ret = recv(self->sockfd, buf, (int)len, flags);
|
||||
#else
|
||||
ret = recv(self->sockfd, buf, len, flags);
|
||||
#endif
|
||||
|
||||
if (0 > ret) {
|
||||
self->internal_error = amqp_os_socket_error();
|
||||
switch (self->internal_error) {
|
||||
case EINTR:
|
||||
goto start;
|
||||
#ifdef _WIN32
|
||||
case WSAEWOULDBLOCK:
|
||||
#else
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
|
||||
case EAGAIN:
|
||||
#endif
|
||||
ret = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD;
|
||||
break;
|
||||
default:
|
||||
ret = AMQP_STATUS_SOCKET_ERROR;
|
||||
}
|
||||
} else if (0 == ret) {
|
||||
ret = AMQP_STATUS_CONNECTION_CLOSED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amqp_tcp_socket_open(void *base, const char *host, int port,
|
||||
struct timeval *timeout) {
|
||||
struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
|
||||
if (-1 != self->sockfd) {
|
||||
return AMQP_STATUS_SOCKET_INUSE;
|
||||
}
|
||||
self->sockfd = amqp_open_socket_noblock(host, port, timeout);
|
||||
if (0 > self->sockfd) {
|
||||
int err = self->sockfd;
|
||||
self->sockfd = -1;
|
||||
return err;
|
||||
}
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
static int amqp_tcp_socket_close(void *base,
|
||||
AMQP_UNUSED amqp_socket_close_enum force) {
|
||||
struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
|
||||
if (-1 == self->sockfd) {
|
||||
return AMQP_STATUS_SOCKET_CLOSED;
|
||||
}
|
||||
|
||||
if (amqp_os_socket_close(self->sockfd)) {
|
||||
return AMQP_STATUS_SOCKET_ERROR;
|
||||
}
|
||||
self->sockfd = -1;
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
static int amqp_tcp_socket_get_sockfd(void *base) {
|
||||
struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
|
||||
return self->sockfd;
|
||||
}
|
||||
|
||||
static void amqp_tcp_socket_delete(void *base) {
|
||||
struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base;
|
||||
|
||||
if (self) {
|
||||
amqp_tcp_socket_close(self, AMQP_SC_NONE);
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct amqp_socket_class_t amqp_tcp_socket_class = {
|
||||
amqp_tcp_socket_send, /* send */
|
||||
amqp_tcp_socket_recv, /* recv */
|
||||
amqp_tcp_socket_open, /* open */
|
||||
amqp_tcp_socket_close, /* close */
|
||||
amqp_tcp_socket_get_sockfd, /* get_sockfd */
|
||||
amqp_tcp_socket_delete /* delete */
|
||||
};
|
||||
|
||||
amqp_socket_t *amqp_tcp_socket_new(amqp_connection_state_t state) {
|
||||
struct amqp_tcp_socket_t *self = calloc(1, sizeof(*self));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
self->klass = &amqp_tcp_socket_class;
|
||||
self->sockfd = -1;
|
||||
|
||||
amqp_set_socket(state, (amqp_socket_t *)self);
|
||||
|
||||
return (amqp_socket_t *)self;
|
||||
}
|
||||
|
||||
void amqp_tcp_socket_set_sockfd(amqp_socket_t *base, int sockfd) {
|
||||
struct amqp_tcp_socket_t *self;
|
||||
if (base->klass != &amqp_tcp_socket_class) {
|
||||
amqp_abort("<%p> is not of type amqp_tcp_socket_t", base);
|
||||
}
|
||||
self = (struct amqp_tcp_socket_t *)base;
|
||||
self->sockfd = sockfd;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/** \file */
|
||||
/*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Michael Steinert are Copyright (c) 2012-2013 Michael
|
||||
* Steinert. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A TCP socket connection.
|
||||
*/
|
||||
|
||||
#ifndef AMQP_TCP_SOCKET_H
|
||||
#define AMQP_TCP_SOCKET_H
|
||||
|
||||
#include <amqp.h>
|
||||
|
||||
AMQP_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* Create a new TCP socket.
|
||||
*
|
||||
* Call amqp_connection_close() to release socket resources.
|
||||
*
|
||||
* \return A new socket object or NULL if an error occurred.
|
||||
*
|
||||
* \since v0.4.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
amqp_socket_t *AMQP_CALL amqp_tcp_socket_new(amqp_connection_state_t state);
|
||||
|
||||
/**
|
||||
* Assign an open file descriptor to a socket object.
|
||||
*
|
||||
* This function must not be used in conjunction with amqp_socket_open(), i.e.
|
||||
* the socket connection should already be open(2) when this function is
|
||||
* called.
|
||||
*
|
||||
* \param [in,out] self A TCP socket object.
|
||||
* \param [in] sockfd An open socket descriptor.
|
||||
*
|
||||
* \since v0.4.0
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
void AMQP_CALL amqp_tcp_socket_set_sockfd(amqp_socket_t *self, int sockfd);
|
||||
|
||||
AMQP_END_DECLS
|
||||
|
||||
#endif /* AMQP_TCP_SOCKET_H */
|
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "amqp_time.h"
|
||||
#include "amqp.h"
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || \
|
||||
defined(__MINGW32__) || defined(__MINGW64__))
|
||||
#define AMQP_WIN_TIMER_API
|
||||
#elif (defined(machintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
|
||||
#define AMQP_MAC_TIMER_API
|
||||
#else
|
||||
#define AMQP_POSIX_TIMER_API
|
||||
#endif
|
||||
|
||||
#ifdef AMQP_WIN_TIMER_API
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
uint64_t amqp_get_monotonic_timestamp(void) {
|
||||
static double NS_PER_COUNT = 0;
|
||||
LARGE_INTEGER perf_count;
|
||||
|
||||
if (0 == NS_PER_COUNT) {
|
||||
LARGE_INTEGER perf_frequency;
|
||||
if (!QueryPerformanceFrequency(&perf_frequency)) {
|
||||
return 0;
|
||||
}
|
||||
NS_PER_COUNT = (double)AMQP_NS_PER_S / perf_frequency.QuadPart;
|
||||
}
|
||||
|
||||
if (!QueryPerformanceCounter(&perf_count)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (uint64_t)(perf_count.QuadPart * NS_PER_COUNT);
|
||||
}
|
||||
#endif /* AMQP_WIN_TIMER_API */
|
||||
|
||||
#ifdef AMQP_MAC_TIMER_API
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
uint64_t amqp_get_monotonic_timestamp(void) {
|
||||
static mach_timebase_info_data_t s_timebase = {0, 0};
|
||||
uint64_t timestamp;
|
||||
|
||||
timestamp = mach_absolute_time();
|
||||
|
||||
if (s_timebase.denom == 0) {
|
||||
mach_timebase_info(&s_timebase);
|
||||
if (0 == s_timebase.denom) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
timestamp *= (uint64_t)s_timebase.numer;
|
||||
timestamp /= (uint64_t)s_timebase.denom;
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
#endif /* AMQP_MAC_TIMER_API */
|
||||
|
||||
#ifdef AMQP_POSIX_TIMER_API
|
||||
#include <time.h>
|
||||
|
||||
uint64_t amqp_get_monotonic_timestamp(void) {
|
||||
#ifdef __hpux
|
||||
return (uint64_t)gethrtime();
|
||||
#else
|
||||
struct timespec tp;
|
||||
if (-1 == clock_gettime(CLOCK_MONOTONIC, &tp)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ((uint64_t)tp.tv_sec * AMQP_NS_PER_S + (uint64_t)tp.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
#endif /* AMQP_POSIX_TIMER_API */
|
||||
|
||||
int amqp_time_from_now(amqp_time_t *time, struct timeval *timeout) {
|
||||
uint64_t now_ns;
|
||||
uint64_t delta_ns;
|
||||
|
||||
assert(NULL != time);
|
||||
|
||||
if (NULL == timeout) {
|
||||
*time = amqp_time_infinite();
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
if (0 == timeout->tv_sec && 0 == timeout->tv_usec) {
|
||||
*time = amqp_time_immediate();
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
if (timeout->tv_sec < 0 || timeout->tv_usec < 0) {
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
delta_ns = (uint64_t)timeout->tv_sec * AMQP_NS_PER_S +
|
||||
(uint64_t)timeout->tv_usec * AMQP_NS_PER_US;
|
||||
|
||||
now_ns = amqp_get_monotonic_timestamp();
|
||||
if (0 == now_ns) {
|
||||
return AMQP_STATUS_TIMER_FAILURE;
|
||||
}
|
||||
|
||||
time->time_point_ns = now_ns + delta_ns;
|
||||
if (now_ns > time->time_point_ns || delta_ns > time->time_point_ns) {
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
int amqp_time_s_from_now(amqp_time_t *time, int seconds) {
|
||||
uint64_t now_ns;
|
||||
uint64_t delta_ns;
|
||||
assert(NULL != time);
|
||||
|
||||
if (0 >= seconds) {
|
||||
*time = amqp_time_infinite();
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
now_ns = amqp_get_monotonic_timestamp();
|
||||
if (0 == now_ns) {
|
||||
return AMQP_STATUS_TIMER_FAILURE;
|
||||
}
|
||||
|
||||
delta_ns = (uint64_t)seconds * AMQP_NS_PER_S;
|
||||
time->time_point_ns = now_ns + delta_ns;
|
||||
if (now_ns > time->time_point_ns || delta_ns > time->time_point_ns) {
|
||||
return AMQP_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
amqp_time_t amqp_time_immediate(void) {
|
||||
amqp_time_t time;
|
||||
time.time_point_ns = 0;
|
||||
return time;
|
||||
}
|
||||
|
||||
amqp_time_t amqp_time_infinite(void) {
|
||||
amqp_time_t time;
|
||||
time.time_point_ns = UINT64_MAX;
|
||||
return time;
|
||||
}
|
||||
|
||||
int amqp_time_ms_until(amqp_time_t time) {
|
||||
uint64_t now_ns;
|
||||
uint64_t delta_ns;
|
||||
int left_ms;
|
||||
|
||||
if (UINT64_MAX == time.time_point_ns) {
|
||||
return -1;
|
||||
}
|
||||
if (0 == time.time_point_ns) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
now_ns = amqp_get_monotonic_timestamp();
|
||||
if (0 == now_ns) {
|
||||
return AMQP_STATUS_TIMER_FAILURE;
|
||||
}
|
||||
|
||||
if (now_ns >= time.time_point_ns) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
delta_ns = time.time_point_ns - now_ns;
|
||||
left_ms = (int)(delta_ns / AMQP_NS_PER_MS);
|
||||
|
||||
return left_ms;
|
||||
}
|
||||
|
||||
int amqp_time_tv_until(amqp_time_t time, struct timeval *in,
|
||||
struct timeval **out) {
|
||||
uint64_t now_ns;
|
||||
uint64_t delta_ns;
|
||||
|
||||
assert(in != NULL);
|
||||
if (UINT64_MAX == time.time_point_ns) {
|
||||
*out = NULL;
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
if (0 == time.time_point_ns) {
|
||||
in->tv_sec = 0;
|
||||
in->tv_usec = 0;
|
||||
*out = in;
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
now_ns = amqp_get_monotonic_timestamp();
|
||||
if (0 == now_ns) {
|
||||
return AMQP_STATUS_TIMER_FAILURE;
|
||||
}
|
||||
|
||||
if (now_ns >= time.time_point_ns) {
|
||||
in->tv_sec = 0;
|
||||
in->tv_usec = 0;
|
||||
*out = in;
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
delta_ns = time.time_point_ns - now_ns;
|
||||
in->tv_sec = (int)(delta_ns / AMQP_NS_PER_S);
|
||||
in->tv_usec = (int)((delta_ns % AMQP_NS_PER_S) / AMQP_NS_PER_US);
|
||||
*out = in;
|
||||
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
int amqp_time_has_past(amqp_time_t time) {
|
||||
uint64_t now_ns;
|
||||
if (UINT64_MAX == time.time_point_ns) {
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
now_ns = amqp_get_monotonic_timestamp();
|
||||
if (0 == now_ns) {
|
||||
return AMQP_STATUS_TIMER_FAILURE;
|
||||
}
|
||||
|
||||
if (now_ns > time.time_point_ns) {
|
||||
return AMQP_STATUS_TIMEOUT;
|
||||
}
|
||||
return AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
amqp_time_t amqp_time_first(amqp_time_t l, amqp_time_t r) {
|
||||
if (l.time_point_ns < r.time_point_ns) {
|
||||
return l;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int amqp_time_equal(amqp_time_t l, amqp_time_t r) {
|
||||
return l.time_point_ns == r.time_point_ns;
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef AMQP_TIMER_H
|
||||
#define AMQP_TIMER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if ((defined(_WIN32)) || (defined(__MINGW32__)) || (defined(__MINGW64__)))
|
||||
#ifndef WINVER
|
||||
#define WINVER 0x0502
|
||||
#endif
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#define AMQP_MS_PER_S 1000
|
||||
#define AMQP_US_PER_MS 1000
|
||||
#define AMQP_NS_PER_S 1000000000
|
||||
#define AMQP_NS_PER_MS 1000000
|
||||
#define AMQP_NS_PER_US 1000
|
||||
|
||||
/* This represents a point in time in reference to a monotonic clock.
|
||||
*
|
||||
* The internal representation is ns, relative to the monotonic clock.
|
||||
*
|
||||
* There are two 'special' values:
|
||||
* - 0: means 'this instant', its meant for polls with a 0-timeout, or
|
||||
* non-blocking option
|
||||
* - UINT64_MAX: means 'at infinity', its mean for polls with an infinite
|
||||
* timeout
|
||||
*/
|
||||
typedef struct amqp_time_t_ { uint64_t time_point_ns; } amqp_time_t;
|
||||
|
||||
/* Gets a monotonic timestamp. This will return 0 if the underlying call to the
|
||||
* system fails.
|
||||
*/
|
||||
uint64_t amqp_get_monotonic_timestamp(void);
|
||||
|
||||
/* Get a amqp_time_t that is timeout from now.
|
||||
* If timeout is NULL, an amqp_time_infinite() is created.
|
||||
* If timeout = {0, 0}, an amqp_time_immediate() is created.
|
||||
*
|
||||
* Returns AMQP_STATUS_OK on success.
|
||||
* AMQP_STATUS_INVALID_PARAMETER if timeout is invalid
|
||||
* AMQP_STATUS_TIMER_FAILURE if the underlying call to get the current timestamp
|
||||
* fails.
|
||||
*/
|
||||
int amqp_time_from_now(amqp_time_t *time, struct timeval *timeout);
|
||||
|
||||
/* Get a amqp_time_t that is seconds from now.
|
||||
* If seconds <= 0, then amqp_time_infinite() is created.
|
||||
*
|
||||
* Returns AMQP_STATUS_OK on success.
|
||||
* AMQP_STATUS_TIMER_FAILURE if the underlying call to get the current timestamp
|
||||
* fails.
|
||||
*/
|
||||
int amqp_time_s_from_now(amqp_time_t *time, int seconds);
|
||||
|
||||
/* Create an immediate amqp_time_t */
|
||||
amqp_time_t amqp_time_immediate(void);
|
||||
|
||||
/* Create an infinite amqp_time_t */
|
||||
amqp_time_t amqp_time_infinite(void);
|
||||
|
||||
/* Gets the number of ms until the amqp_time_t, suitable for the timeout
|
||||
* parameter in poll().
|
||||
*
|
||||
* -1 will be returned for amqp_time_infinite values.
|
||||
* 0 will be returned for amqp_time_immediate values.
|
||||
* AMQP_STATUS_TIMEOUT will be returned if time was in the past.
|
||||
* AMQP_STATUS_TIMER_FAILURE will be returned if the underlying call to get the
|
||||
* current timestamp fails.
|
||||
*/
|
||||
int amqp_time_ms_until(amqp_time_t time);
|
||||
|
||||
/* Gets a timeval filled in with the time until amqp_time_t. Suitable for the
|
||||
* parameter in select().
|
||||
*
|
||||
* The in parameter specifies a storage location for *out.
|
||||
* If time is an inf timeout, then *out = NULL.
|
||||
* If time is a 0-timeout or the timer has expired, then *out = {0, 0}
|
||||
* Otherwise *out is set to the time left on the time.
|
||||
*
|
||||
* AMQP_STATUS_OK will be returned if successfully filled.
|
||||
* AMQP_STATUS_TIMER_FAILURE is returned when the underlying call to get the
|
||||
* current timestamp fails.
|
||||
*/
|
||||
int amqp_time_tv_until(amqp_time_t time, struct timeval *in,
|
||||
struct timeval **out);
|
||||
|
||||
/* Test whether current time is past the provided time.
|
||||
*
|
||||
* TODO: this isn't a great interface to use. Fix this.
|
||||
*
|
||||
* Return AMQP_STATUS_OK if time has not past
|
||||
* Return AMQP_STATUS_TIMEOUT if time has past
|
||||
* Return AMQP_STATUS_TIMER_FAILURE if the underlying call to get the current
|
||||
* timestamp fails.
|
||||
*/
|
||||
int amqp_time_has_past(amqp_time_t time);
|
||||
|
||||
/* Return the time value that happens first */
|
||||
amqp_time_t amqp_time_first(amqp_time_t l, amqp_time_t r);
|
||||
|
||||
int amqp_time_equal(amqp_time_t l, amqp_time_t r);
|
||||
#endif /* AMQP_TIMER_H */
|
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "amqp_private.h"
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void amqp_default_connection_info(struct amqp_connection_info *ci) {
|
||||
/* Apply defaults */
|
||||
ci->user = "guest";
|
||||
ci->password = "guest";
|
||||
ci->host = "localhost";
|
||||
ci->port = 5672;
|
||||
ci->vhost = "/";
|
||||
ci->ssl = 0;
|
||||
}
|
||||
|
||||
/* Scan for the next delimiter, handling percent-encodings on the way. */
|
||||
static char find_delim(char **pp, int colon_and_at_sign_are_delims) {
|
||||
char *from = *pp;
|
||||
char *to = from;
|
||||
|
||||
for (;;) {
|
||||
char ch = *from++;
|
||||
|
||||
switch (ch) {
|
||||
case ':':
|
||||
case '@':
|
||||
if (!colon_and_at_sign_are_delims) {
|
||||
*to++ = ch;
|
||||
break;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
case 0:
|
||||
case '/':
|
||||
case '?':
|
||||
case '#':
|
||||
case '[':
|
||||
case ']':
|
||||
*to = 0;
|
||||
*pp = from;
|
||||
return ch;
|
||||
|
||||
case '%': {
|
||||
unsigned int val;
|
||||
int chars;
|
||||
int res = sscanf(from, "%2x%n", &val, &chars);
|
||||
|
||||
if (res == EOF || res < 1 || chars != 2 || val > CHAR_MAX)
|
||||
/* Return a surprising delimiter to
|
||||
force an error. */
|
||||
{
|
||||
return '%';
|
||||
}
|
||||
|
||||
*to++ = (char)val;
|
||||
from += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
*to++ = ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse an AMQP URL into its component parts. */
|
||||
int amqp_parse_url(char *url, struct amqp_connection_info *parsed) {
|
||||
int res = AMQP_STATUS_BAD_URL;
|
||||
char delim;
|
||||
char *start;
|
||||
char *host;
|
||||
char *port = NULL;
|
||||
|
||||
amqp_default_connection_info(parsed);
|
||||
|
||||
/* check the prefix */
|
||||
if (!strncmp(url, "amqp://", 7)) {
|
||||
/* do nothing */
|
||||
} else if (!strncmp(url, "amqps://", 8)) {
|
||||
parsed->port = 5671;
|
||||
parsed->ssl = 1;
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
|
||||
host = start = url += (parsed->ssl ? 8 : 7);
|
||||
delim = find_delim(&url, 1);
|
||||
|
||||
if (delim == ':') {
|
||||
/* The colon could be introducing the port or the
|
||||
password part of the userinfo. We don't know yet,
|
||||
so stash the preceding component. */
|
||||
port = start = url;
|
||||
delim = find_delim(&url, 1);
|
||||
}
|
||||
|
||||
if (delim == '@') {
|
||||
/* What might have been the host and port were in fact
|
||||
the username and password */
|
||||
parsed->user = host;
|
||||
if (port) {
|
||||
parsed->password = port;
|
||||
}
|
||||
|
||||
port = NULL;
|
||||
host = start = url;
|
||||
delim = find_delim(&url, 1);
|
||||
}
|
||||
|
||||
if (delim == '[') {
|
||||
/* IPv6 address. The bracket should be the first
|
||||
character in the host. */
|
||||
if (host != start || *host != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
start = url;
|
||||
delim = find_delim(&url, 0);
|
||||
|
||||
if (delim != ']') {
|
||||
goto out;
|
||||
}
|
||||
|
||||
parsed->host = start;
|
||||
start = url;
|
||||
delim = find_delim(&url, 1);
|
||||
|
||||
/* Closing bracket should be the last character in the
|
||||
host. */
|
||||
if (*start != 0) {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* If we haven't seen the host yet, this is it. */
|
||||
if (*host != 0) {
|
||||
parsed->host = host;
|
||||
}
|
||||
}
|
||||
|
||||
if (delim == ':') {
|
||||
port = start = url;
|
||||
delim = find_delim(&url, 1);
|
||||
}
|
||||
|
||||
if (port) {
|
||||
char *end;
|
||||
long portnum = strtol(port, &end, 10);
|
||||
|
||||
if (port == end || *end != 0 || portnum < 0 || portnum > 65535) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
parsed->port = portnum;
|
||||
}
|
||||
|
||||
if (delim == '/') {
|
||||
start = url;
|
||||
delim = find_delim(&url, 1);
|
||||
|
||||
if (delim != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
parsed->vhost = start;
|
||||
res = AMQP_STATUS_OK;
|
||||
} else if (delim == 0) {
|
||||
res = AMQP_STATUS_OK;
|
||||
}
|
||||
|
||||
/* Any other delimiter is bad, and we will return AMQP_STATUS_BAD_AMQP_URL. */
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
|
@ -1,785 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MIT
|
||||
#
|
||||
# Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
# Alan Antonuk. All Rights Reserved.
|
||||
#
|
||||
# Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
# VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation
|
||||
# files (the "Software"), to deal in the Software without
|
||||
# restriction, including without limitation the rights to use, copy,
|
||||
# modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
# of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
from __future__ import nested_scopes
|
||||
from __future__ import division
|
||||
|
||||
from amqp_codegen import *
|
||||
import string
|
||||
import re
|
||||
|
||||
|
||||
class Emitter(object):
|
||||
"""An object the trivially emits generated code lines.
|
||||
|
||||
This largely exists to be wrapped by more sophisticated emitter
|
||||
classes.
|
||||
"""
|
||||
|
||||
def __init__(self, prefix):
|
||||
self.prefix = prefix
|
||||
|
||||
def emit(self, line):
|
||||
"""Emit a line of generated code."""
|
||||
print self.prefix + line
|
||||
|
||||
|
||||
class BitDecoder(object):
|
||||
"""An emitter object that keeps track of the state involved in
|
||||
decoding the AMQP bit type."""
|
||||
|
||||
def __init__(self, emitter):
|
||||
self.emitter = emitter
|
||||
self.bit = 0
|
||||
|
||||
def emit(self, line):
|
||||
self.bit = 0
|
||||
self.emitter.emit(line)
|
||||
|
||||
def decode_bit(self, lvalue):
|
||||
"""Generate code to decode a value of the AMQP bit type into
|
||||
the given lvalue."""
|
||||
if self.bit == 0:
|
||||
self.emitter.emit("if (!amqp_decode_8(encoded, &offset, &bit_buffer)) return AMQP_STATUS_BAD_AMQP_DATA;")
|
||||
|
||||
self.emitter.emit("%s = (bit_buffer & (1 << %d)) ? 1 : 0;"
|
||||
% (lvalue, self.bit))
|
||||
self.bit += 1
|
||||
if self.bit == 8:
|
||||
self.bit = 0
|
||||
|
||||
|
||||
class BitEncoder(object):
|
||||
"""An emitter object that keeps track of the state involved in
|
||||
encoding the AMQP bit type."""
|
||||
|
||||
def __init__(self, emitter):
|
||||
self.emitter = emitter
|
||||
self.bit = 0
|
||||
|
||||
def flush(self):
|
||||
"""Flush the state associated with AMQP bit types."""
|
||||
if self.bit:
|
||||
self.emitter.emit("if (!amqp_encode_8(encoded, &offset, bit_buffer)) return AMQP_STATUS_BAD_AMQP_DATA;")
|
||||
self.bit = 0
|
||||
|
||||
def emit(self, line):
|
||||
self.flush()
|
||||
self.emitter.emit(line)
|
||||
|
||||
def encode_bit(self, value):
|
||||
"""Generate code to encode a value of the AMQP bit type from
|
||||
the given value."""
|
||||
if self.bit == 0:
|
||||
self.emitter.emit("bit_buffer = 0;")
|
||||
|
||||
self.emitter.emit("if (%s) bit_buffer |= (1 << %d);"
|
||||
% (value, self.bit))
|
||||
self.bit += 1
|
||||
if self.bit == 8:
|
||||
self.flush()
|
||||
|
||||
|
||||
class SimpleType(object):
|
||||
"""A AMQP type that corresponds to a simple scalar C value of a
|
||||
certain width."""
|
||||
|
||||
def __init__(self, bits):
|
||||
self.bits = bits
|
||||
self.ctype = "uint%d_t" % (bits,)
|
||||
|
||||
def decode(self, emitter, lvalue):
|
||||
emitter.emit("if (!amqp_decode_%d(encoded, &offset, &%s)) return AMQP_STATUS_BAD_AMQP_DATA;" % (self.bits, lvalue))
|
||||
|
||||
def encode(self, emitter, value):
|
||||
emitter.emit("if (!amqp_encode_%d(encoded, &offset, %s)) return AMQP_STATUS_BAD_AMQP_DATA;" % (self.bits, value))
|
||||
|
||||
def literal(self, value):
|
||||
return value
|
||||
|
||||
class StrType(object):
|
||||
"""The AMQP shortstr or longstr types."""
|
||||
|
||||
def __init__(self, lenbits):
|
||||
self.lenbits = lenbits
|
||||
self.ctype = "amqp_bytes_t"
|
||||
|
||||
def decode(self, emitter, lvalue):
|
||||
emitter.emit("{")
|
||||
emitter.emit(" uint%d_t len;" % (self.lenbits,))
|
||||
emitter.emit(" if (!amqp_decode_%d(encoded, &offset, &len)" % (self.lenbits,))
|
||||
emitter.emit(" || !amqp_decode_bytes(encoded, &offset, &%s, len))" % (lvalue,))
|
||||
emitter.emit(" return AMQP_STATUS_BAD_AMQP_DATA;")
|
||||
emitter.emit("}")
|
||||
|
||||
def encode(self, emitter, value):
|
||||
emitter.emit("if (UINT%d_MAX < %s.len" % (self.lenbits, value))
|
||||
emitter.emit(" || !amqp_encode_%d(encoded, &offset, (uint%d_t)%s.len)" %
|
||||
(self.lenbits, self.lenbits, value))
|
||||
emitter.emit(" || !amqp_encode_bytes(encoded, &offset, %s))" % (value,))
|
||||
emitter.emit(" return AMQP_STATUS_BAD_AMQP_DATA;")
|
||||
|
||||
def literal(self, value):
|
||||
if value != '':
|
||||
raise NotImplementedError()
|
||||
|
||||
return "amqp_empty_bytes"
|
||||
|
||||
class BitType(object):
|
||||
"""The AMQP bit type."""
|
||||
|
||||
def __init__(self):
|
||||
self.ctype = "amqp_boolean_t"
|
||||
|
||||
def decode(self, emitter, lvalue):
|
||||
emitter.decode_bit(lvalue)
|
||||
|
||||
def encode(self, emitter, value):
|
||||
emitter.encode_bit(value)
|
||||
|
||||
def literal(self, value):
|
||||
return {True: 1, False: 0}[value]
|
||||
|
||||
class TableType(object):
|
||||
"""The AMQP table type."""
|
||||
|
||||
def __init__(self):
|
||||
self.ctype = "amqp_table_t"
|
||||
|
||||
def decode(self, emitter, lvalue):
|
||||
emitter.emit("{")
|
||||
emitter.emit(" int res = amqp_decode_table(encoded, pool, &(%s), &offset);" % (lvalue,))
|
||||
emitter.emit(" if (res < 0) return res;")
|
||||
emitter.emit("}")
|
||||
|
||||
def encode(self, emitter, value):
|
||||
emitter.emit("{")
|
||||
emitter.emit(" int res = amqp_encode_table(encoded, &(%s), &offset);" % (value,))
|
||||
emitter.emit(" if (res < 0) return res;")
|
||||
emitter.emit("}")
|
||||
|
||||
def literal(self, value):
|
||||
raise NotImplementedError()
|
||||
|
||||
types = {
|
||||
'octet': SimpleType(8),
|
||||
'short': SimpleType(16),
|
||||
'long': SimpleType(32),
|
||||
'longlong': SimpleType(64),
|
||||
'shortstr': StrType(8),
|
||||
'longstr': StrType(32),
|
||||
'bit': BitType(),
|
||||
'table': TableType(),
|
||||
'timestamp': SimpleType(64),
|
||||
}
|
||||
|
||||
def typeFor(spec, f):
|
||||
"""Get a representation of the AMQP type of a field."""
|
||||
return types[spec.resolveDomain(f.domain)]
|
||||
|
||||
def c_ize(s):
|
||||
s = s.replace('-', '_')
|
||||
s = s.replace(' ', '_')
|
||||
return s
|
||||
|
||||
# When generating API functions corresponding to synchronous methods,
|
||||
# we need some information that isn't in the protocol def: Some
|
||||
# methods should not be exposed, indicated here by a False value.
|
||||
# Some methods should be exposed but certain fields should not be
|
||||
# exposed as parameters.
|
||||
apiMethodInfo = {
|
||||
"amqp_connection_start": False, # application code should not use this
|
||||
"amqp_connection_secure": False, # application code should not use this
|
||||
"amqp_connection_tune": False, # application code should not use this
|
||||
"amqp_connection_open": False, # application code should not use this
|
||||
"amqp_connection_close": False, # needs special handling
|
||||
"amqp_channel_open": ["out_of_band"],
|
||||
"amqp_channel_close": False, # needs special handling
|
||||
"amqp_access_request": False, # huh?
|
||||
"amqp_basic_get": False, # get-ok has content
|
||||
}
|
||||
|
||||
# When generating API functions corresponding to synchronous methods,
|
||||
# some fields should be suppressed everywhere. This dict names those
|
||||
# fields, and the fixed values to use for them.
|
||||
apiMethodsSuppressArgs = {"ticket": 0, "nowait": False}
|
||||
|
||||
AmqpMethod.defName = lambda m: cConstantName(c_ize(m.klass.name) + '_' + c_ize(m.name) + "_method")
|
||||
AmqpMethod.fullName = lambda m: "amqp_%s_%s" % (c_ize(m.klass.name), c_ize(m.name))
|
||||
AmqpMethod.structName = lambda m: m.fullName() + "_t"
|
||||
|
||||
AmqpClass.structName = lambda c: "amqp_" + c_ize(c.name) + "_properties_t"
|
||||
|
||||
def methodApiPrototype(m):
|
||||
fn = m.fullName()
|
||||
info = apiMethodInfo.get(fn, [])
|
||||
|
||||
docs = "/**\n * %s\n *\n" % (fn)
|
||||
docs += " * @param [in] state connection state\n"
|
||||
docs += " * @param [in] channel the channel to do the RPC on\n"
|
||||
|
||||
args = []
|
||||
for f in m.arguments:
|
||||
n = c_ize(f.name)
|
||||
if n in apiMethodsSuppressArgs or n in info:
|
||||
continue
|
||||
|
||||
args.append(", ")
|
||||
args.append(typeFor(m.klass.spec, f).ctype)
|
||||
args.append(" ")
|
||||
args.append(n)
|
||||
docs += " * @param [in] %s %s\n" % (n, n)
|
||||
|
||||
docs += " * @returns %s_ok_t\n" % (fn)
|
||||
docs += " */\n"
|
||||
|
||||
return "%sAMQP_PUBLIC_FUNCTION\n%s_ok_t *\nAMQP_CALL %s(amqp_connection_state_t state, amqp_channel_t channel%s)" % (docs, fn, fn, ''.join(args))
|
||||
|
||||
AmqpMethod.apiPrototype = methodApiPrototype
|
||||
|
||||
def cConstantName(s):
|
||||
return 'AMQP_' + '_'.join(re.split('[- ]', s.upper()))
|
||||
|
||||
def cFlagName(c, f):
|
||||
return cConstantName(c.name + '_' + f.name) + '_FLAG'
|
||||
|
||||
def genErl(spec):
|
||||
def fieldTempList(fields):
|
||||
return '[' + ', '.join(['F' + str(f.index) for f in fields]) + ']'
|
||||
|
||||
def fieldMapList(fields):
|
||||
return ', '.join([c_ize(f.name) + " = F" + str(f.index) for f in fields])
|
||||
|
||||
def genLookupMethodName(m):
|
||||
print ' case %s: return "%s";' % (m.defName(), m.defName())
|
||||
|
||||
def genDecodeMethodFields(m):
|
||||
print " case %s: {" % (m.defName(),)
|
||||
print " %s *m = (%s *) amqp_pool_alloc(pool, sizeof(%s));" % \
|
||||
(m.structName(), m.structName(), m.structName())
|
||||
print " if (m == NULL) { return AMQP_STATUS_NO_MEMORY; }"
|
||||
|
||||
emitter = BitDecoder(Emitter(" "))
|
||||
for f in m.arguments:
|
||||
typeFor(spec, f).decode(emitter, "m->"+c_ize(f.name))
|
||||
|
||||
print " *decoded = m;"
|
||||
print " return 0;"
|
||||
print " }"
|
||||
|
||||
def genDecodeProperties(c):
|
||||
print " case %d: {" % (c.index,)
|
||||
print " %s *p = (%s *) amqp_pool_alloc(pool, sizeof(%s));" % \
|
||||
(c.structName(), c.structName(), c.structName())
|
||||
print " if (p == NULL) { return AMQP_STATUS_NO_MEMORY; }"
|
||||
print " p->_flags = flags;"
|
||||
|
||||
emitter = Emitter(" ")
|
||||
for f in c.fields:
|
||||
emitter.emit("if (flags & %s) {" % (cFlagName(c, f),))
|
||||
typeFor(spec, f).decode(emitter, "p->"+c_ize(f.name))
|
||||
emitter.emit("}")
|
||||
|
||||
print " *decoded = p;"
|
||||
print " return 0;"
|
||||
print " }"
|
||||
|
||||
def genEncodeMethodFields(m):
|
||||
print " case %s: {" % (m.defName(),)
|
||||
if m.arguments:
|
||||
print " %s *m = (%s *) decoded;" % (m.structName(), m.structName())
|
||||
|
||||
emitter = BitEncoder(Emitter(" "))
|
||||
for f in m.arguments:
|
||||
typeFor(spec, f).encode(emitter, "m->"+c_ize(f.name))
|
||||
emitter.flush()
|
||||
|
||||
print " return (int)offset;"
|
||||
print " }"
|
||||
|
||||
def genEncodeProperties(c):
|
||||
print " case %d: {" % (c.index,)
|
||||
if c.fields:
|
||||
print " %s *p = (%s *) decoded;" % (c.structName(), c.structName())
|
||||
|
||||
emitter = Emitter(" ")
|
||||
for f in c.fields:
|
||||
emitter.emit(" if (flags & %s) {" % (cFlagName(c, f),))
|
||||
typeFor(spec, f).encode(emitter, "p->"+c_ize(f.name))
|
||||
emitter.emit("}")
|
||||
|
||||
print " return (int)offset;"
|
||||
print " }"
|
||||
|
||||
methods = spec.allMethods()
|
||||
|
||||
print """/* Generated code. Do not edit. Edit and re-run codegen.py instead.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "amqp_private.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
"""
|
||||
|
||||
print """
|
||||
char const *amqp_constant_name(int constantNumber) {
|
||||
switch (constantNumber) {"""
|
||||
for (c,v,cls) in spec.constants:
|
||||
print " case %s: return \"%s\";" % (cConstantName(c), cConstantName(c))
|
||||
print """ default: return "(unknown)";
|
||||
}
|
||||
}"""
|
||||
|
||||
print """
|
||||
amqp_boolean_t amqp_constant_is_hard_error(int constantNumber) {
|
||||
switch (constantNumber) {"""
|
||||
for (c,v,cls) in spec.constants:
|
||||
if cls == 'hard-error':
|
||||
print " case %s: return 1;" % (cConstantName(c),)
|
||||
print """ default: return 0;
|
||||
}
|
||||
}"""
|
||||
|
||||
print """
|
||||
char const *amqp_method_name(amqp_method_number_t methodNumber) {
|
||||
switch (methodNumber) {"""
|
||||
for m in methods: genLookupMethodName(m)
|
||||
print """ default: return NULL;
|
||||
}
|
||||
}"""
|
||||
|
||||
print """
|
||||
amqp_boolean_t amqp_method_has_content(amqp_method_number_t methodNumber) {
|
||||
switch (methodNumber) {"""
|
||||
for m in methods:
|
||||
if m.hasContent:
|
||||
print ' case %s: return 1;' % (m.defName())
|
||||
print """ default: return 0;
|
||||
}
|
||||
}"""
|
||||
|
||||
print """
|
||||
int amqp_decode_method(amqp_method_number_t methodNumber,
|
||||
amqp_pool_t *pool,
|
||||
amqp_bytes_t encoded,
|
||||
void **decoded)
|
||||
{
|
||||
size_t offset = 0;
|
||||
uint8_t bit_buffer;
|
||||
|
||||
switch (methodNumber) {"""
|
||||
for m in methods: genDecodeMethodFields(m)
|
||||
print """ default: return AMQP_STATUS_UNKNOWN_METHOD;
|
||||
}
|
||||
}"""
|
||||
|
||||
print """
|
||||
int amqp_decode_properties(uint16_t class_id,
|
||||
amqp_pool_t *pool,
|
||||
amqp_bytes_t encoded,
|
||||
void **decoded)
|
||||
{
|
||||
size_t offset = 0;
|
||||
|
||||
amqp_flags_t flags = 0;
|
||||
int flagword_index = 0;
|
||||
uint16_t partial_flags;
|
||||
|
||||
do {
|
||||
if (!amqp_decode_16(encoded, &offset, &partial_flags))
|
||||
return AMQP_STATUS_BAD_AMQP_DATA;
|
||||
flags |= (partial_flags << (flagword_index * 16));
|
||||
flagword_index++;
|
||||
} while (partial_flags & 1);
|
||||
|
||||
switch (class_id) {"""
|
||||
for c in spec.allClasses(): genDecodeProperties(c)
|
||||
print """ default: return AMQP_STATUS_UNKNOWN_CLASS;
|
||||
}
|
||||
}"""
|
||||
|
||||
print """
|
||||
int amqp_encode_method(amqp_method_number_t methodNumber,
|
||||
void *decoded,
|
||||
amqp_bytes_t encoded)
|
||||
{
|
||||
size_t offset = 0;
|
||||
uint8_t bit_buffer;
|
||||
|
||||
switch (methodNumber) {"""
|
||||
for m in methods: genEncodeMethodFields(m)
|
||||
print """ default: return AMQP_STATUS_UNKNOWN_METHOD;
|
||||
}
|
||||
}"""
|
||||
|
||||
print """
|
||||
int amqp_encode_properties(uint16_t class_id,
|
||||
void *decoded,
|
||||
amqp_bytes_t encoded)
|
||||
{
|
||||
size_t offset = 0;
|
||||
|
||||
/* Cheat, and get the flags out generically, relying on the
|
||||
similarity of structure between classes */
|
||||
amqp_flags_t flags = * (amqp_flags_t *) decoded; /* cheating! */
|
||||
|
||||
{
|
||||
/* We take a copy of flags to avoid destroying it, as it is used
|
||||
in the autogenerated code below. */
|
||||
amqp_flags_t remaining_flags = flags;
|
||||
do {
|
||||
amqp_flags_t remainder = remaining_flags >> 16;
|
||||
uint16_t partial_flags = remaining_flags & 0xFFFE;
|
||||
if (remainder != 0) { partial_flags |= 1; }
|
||||
if (!amqp_encode_16(encoded, &offset, partial_flags))
|
||||
return AMQP_STATUS_BAD_AMQP_DATA;
|
||||
remaining_flags = remainder;
|
||||
} while (remaining_flags != 0);
|
||||
}
|
||||
|
||||
switch (class_id) {"""
|
||||
for c in spec.allClasses(): genEncodeProperties(c)
|
||||
print """ default: return AMQP_STATUS_UNKNOWN_CLASS;
|
||||
}
|
||||
}"""
|
||||
|
||||
for m in methods:
|
||||
if not m.isSynchronous:
|
||||
continue
|
||||
|
||||
info = apiMethodInfo.get(m.fullName(), [])
|
||||
if info is False:
|
||||
continue
|
||||
|
||||
print
|
||||
print m.apiPrototype()
|
||||
print "{"
|
||||
print " %s req;" % (m.structName(),)
|
||||
|
||||
for f in m.arguments:
|
||||
n = c_ize(f.name)
|
||||
|
||||
val = apiMethodsSuppressArgs.get(n)
|
||||
if val is None and n in info:
|
||||
val = f.defaultvalue
|
||||
|
||||
if val is None:
|
||||
val = n
|
||||
else:
|
||||
val = typeFor(spec, f).literal(val)
|
||||
|
||||
|
||||
print " req.%s = %s;" % (n, val)
|
||||
|
||||
reply = cConstantName(c_ize(m.klass.name) + '_' + c_ize(m.name)
|
||||
+ "_ok_method")
|
||||
print """
|
||||
return amqp_simple_rpc_decoded(state, channel, %s, %s, &req);
|
||||
}
|
||||
""" % (m.defName(), reply)
|
||||
|
||||
def genHrl(spec):
|
||||
def fieldDeclList(fields):
|
||||
if fields:
|
||||
return ''.join([" %s %s; /**< %s */\n" % (typeFor(spec, f).ctype,
|
||||
c_ize(f.name), f.name)
|
||||
for f in fields])
|
||||
else:
|
||||
return " char dummy; /**< Dummy field to avoid empty struct */\n"
|
||||
|
||||
def propDeclList(fields):
|
||||
return ''.join([" %s %s;\n" % (typeFor(spec, f).ctype, c_ize(f.name))
|
||||
for f in fields
|
||||
if spec.resolveDomain(f.domain) != 'bit'])
|
||||
|
||||
methods = spec.allMethods()
|
||||
|
||||
print """/* Generated code. Do not edit. Edit and re-run codegen.py instead.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MIT
|
||||
*
|
||||
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
||||
* Alan Antonuk. All Rights Reserved.
|
||||
*
|
||||
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
||||
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** @file amqp_framing.h */
|
||||
#ifndef AMQP_FRAMING_H
|
||||
#define AMQP_FRAMING_H
|
||||
|
||||
#include <amqp.h>
|
||||
|
||||
AMQP_BEGIN_DECLS
|
||||
"""
|
||||
print "#define AMQP_PROTOCOL_VERSION_MAJOR %d /**< AMQP protocol version major */" % (spec.major)
|
||||
print "#define AMQP_PROTOCOL_VERSION_MINOR %d /**< AMQP protocol version minor */" % (spec.minor)
|
||||
print "#define AMQP_PROTOCOL_VERSION_REVISION %d /**< AMQP protocol version revision */" % (spec.revision)
|
||||
print "#define AMQP_PROTOCOL_PORT %d /**< Default AMQP Port */" % (spec.port)
|
||||
|
||||
for (c,v,cls) in spec.constants:
|
||||
print "#define %s %s /**< Constant: %s */" % (cConstantName(c), v, c)
|
||||
print
|
||||
|
||||
print """/* Function prototypes. */
|
||||
|
||||
/**
|
||||
* Get constant name string from constant
|
||||
*
|
||||
* @param [in] constantNumber constant to get the name of
|
||||
* @returns string describing the constant. String is managed by
|
||||
* the library and should not be free()'d by the program
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
char const *
|
||||
AMQP_CALL amqp_constant_name(int constantNumber);
|
||||
|
||||
/**
|
||||
* Checks to see if a constant is a hard error
|
||||
*
|
||||
* A hard error occurs when something severe enough
|
||||
* happens that the connection must be closed.
|
||||
*
|
||||
* @param [in] constantNumber the error constant
|
||||
* @returns true if its a hard error, false otherwise
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
amqp_boolean_t
|
||||
AMQP_CALL amqp_constant_is_hard_error(int constantNumber);
|
||||
|
||||
/**
|
||||
* Get method name string from method number
|
||||
*
|
||||
* @param [in] methodNumber the method number
|
||||
* @returns method name string. String is managed by the library
|
||||
* and should not be freed()'d by the program
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
char const *
|
||||
AMQP_CALL amqp_method_name(amqp_method_number_t methodNumber);
|
||||
|
||||
/**
|
||||
* Check whether a method has content
|
||||
*
|
||||
* A method that has content will receive the method frame
|
||||
* a properties frame, then 1 to N body frames
|
||||
*
|
||||
* @param [in] methodNumber the method number
|
||||
* @returns true if method has content, false otherwise
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
amqp_boolean_t
|
||||
AMQP_CALL amqp_method_has_content(amqp_method_number_t methodNumber);
|
||||
|
||||
/**
|
||||
* Decodes a method from AMQP wireformat
|
||||
*
|
||||
* @param [in] methodNumber the method number for the decoded parameter
|
||||
* @param [in] pool the memory pool to allocate the decoded method from
|
||||
* @param [in] encoded the encoded byte string buffer
|
||||
* @param [out] decoded pointer to the decoded method struct
|
||||
* @returns 0 on success, an error code otherwise
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
int
|
||||
AMQP_CALL amqp_decode_method(amqp_method_number_t methodNumber,
|
||||
amqp_pool_t *pool,
|
||||
amqp_bytes_t encoded,
|
||||
void **decoded);
|
||||
|
||||
/**
|
||||
* Decodes a header frame properties structure from AMQP wireformat
|
||||
*
|
||||
* @param [in] class_id the class id for the decoded parameter
|
||||
* @param [in] pool the memory pool to allocate the decoded properties from
|
||||
* @param [in] encoded the encoded byte string buffer
|
||||
* @param [out] decoded pointer to the decoded properties struct
|
||||
* @returns 0 on success, an error code otherwise
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
int
|
||||
AMQP_CALL amqp_decode_properties(uint16_t class_id,
|
||||
amqp_pool_t *pool,
|
||||
amqp_bytes_t encoded,
|
||||
void **decoded);
|
||||
|
||||
/**
|
||||
* Encodes a method structure in AMQP wireformat
|
||||
*
|
||||
* @param [in] methodNumber the method number for the decoded parameter
|
||||
* @param [in] decoded the method structure (e.g., amqp_connection_start_t)
|
||||
* @param [in] encoded an allocated byte buffer for the encoded method
|
||||
* structure to be written to. If the buffer isn't large enough
|
||||
* to hold the encoded method, an error code will be returned.
|
||||
* @returns 0 on success, an error code otherwise.
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
int
|
||||
AMQP_CALL amqp_encode_method(amqp_method_number_t methodNumber,
|
||||
void *decoded,
|
||||
amqp_bytes_t encoded);
|
||||
|
||||
/**
|
||||
* Encodes a properties structure in AMQP wireformat
|
||||
*
|
||||
* @param [in] class_id the class id for the decoded parameter
|
||||
* @param [in] decoded the properties structure (e.g., amqp_basic_properties_t)
|
||||
* @param [in] encoded an allocated byte buffer for the encoded properties to written to.
|
||||
* If the buffer isn't large enough to hold the encoded method, an
|
||||
* an error code will be returned
|
||||
* @returns 0 on success, an error code otherwise.
|
||||
*/
|
||||
AMQP_PUBLIC_FUNCTION
|
||||
int
|
||||
AMQP_CALL amqp_encode_properties(uint16_t class_id,
|
||||
void *decoded,
|
||||
amqp_bytes_t encoded);
|
||||
"""
|
||||
|
||||
print "/* Method field records. */\n"
|
||||
for m in methods:
|
||||
methodid = m.klass.index << 16 | m.index
|
||||
print "#define %s ((amqp_method_number_t) 0x%.08X) /**< %s.%s method id @internal %d, %d; %d */" % \
|
||||
(m.defName(),
|
||||
methodid,
|
||||
m.klass.name,
|
||||
m.name,
|
||||
m.klass.index,
|
||||
m.index,
|
||||
methodid)
|
||||
print "/** %s.%s method fields */\ntypedef struct %s_ {\n%s} %s;\n" % \
|
||||
(m.klass.name, m.name, m.structName(), fieldDeclList(m.arguments), m.structName())
|
||||
|
||||
print "/* Class property records. */"
|
||||
for c in spec.allClasses():
|
||||
print "#define %s (0x%.04X) /**< %s class id @internal %d */" % \
|
||||
(cConstantName(c.name + "_class"), c.index, c.name, c.index)
|
||||
index = 0
|
||||
for f in c.fields:
|
||||
if index % 16 == 15:
|
||||
index = index + 1
|
||||
shortnum = index // 16
|
||||
partialindex = 15 - (index % 16)
|
||||
bitindex = shortnum * 16 + partialindex
|
||||
print '#define %s (1 << %d) /**< %s.%s property flag */' % (cFlagName(c, f), bitindex, c.name, f.name)
|
||||
index = index + 1
|
||||
print "/** %s class properties */\ntypedef struct %s_ {\n amqp_flags_t _flags; /**< bit-mask of set fields */\n%s} %s;\n" % \
|
||||
(c.name,
|
||||
c.structName(),
|
||||
fieldDeclList(c.fields),
|
||||
c.structName())
|
||||
|
||||
print "/* API functions for methods */\n"
|
||||
|
||||
for m in methods:
|
||||
if m.isSynchronous and apiMethodInfo.get(m.fullName()) is not False:
|
||||
print "%s;" % (m.apiPrototype(),)
|
||||
|
||||
print """
|
||||
AMQP_END_DECLS
|
||||
|
||||
#endif /* AMQP_FRAMING_H */"""
|
||||
|
||||
def generateErl(specPath):
|
||||
genErl(AmqpSpec(specPath))
|
||||
|
||||
def generateHrl(specPath):
|
||||
genHrl(AmqpSpec(specPath))
|
||||
|
||||
if __name__ == "__main__":
|
||||
do_main(generateHrl, generateErl)
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue