First release of open-appsec source code

This commit is contained in:
roybarda
2022-10-26 19:33:19 +03:00
parent 3883109caf
commit a883352f79
1353 changed files with 276290 additions and 1 deletions

200
core/include/general/buffer.h Executable file
View File

@@ -0,0 +1,200 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __BUFFER_H__
#define __BUFFER_H__
#include <vector>
#include <string>
#include <memory>
#include "cereal/types/vector.hpp"
#include "cereal/types/memory.hpp"
#include "maybe_res.h"
#include "debug.h"
class Buffer final
{
public:
// Indication of the type of memory that is held by the system:
// OWNED - The system allocated the memory and is resposible for releasing it.
// STATIC - The memory is such that is always availabe and doesn't require releasing.
// VOLATILE - The memory was allocated outside of the system and is only availabe for the duration of the
// instance. This memory may require the system to later duplicate (and does change it to OWNED
// memeory).
enum class MemoryType
{
OWNED, STATIC, VOLATILE
};
private:
// Indication of the volatility of the memory.
// OWNED and STATIC type of memory are not volatile, and are marked NONE.
// The initial VOLATILE instance is guaranteed to have the volatile memory available while that instance exists,
// and is marked PRIMARY.
// Instances that are created based on an existing VOLATILE instance are marked as SECONDARY. They are guaranteed
// to have the memory available to thme only as long as the PRIMARY instance exists. If such SECONDARY instance
// continues to exists at the time when the PRIMARY instance is destoryed, then a copy of the memory (of which the
// I/S will be the owner) needs to be made turning the instance from VOLATILE to OWNED.
enum class Volatility
{
NONE, PRIMARY, SECONDARY
};
// The "DataContainer" class represent a shared piece of memory - so if two idifferent buffers buffers
// can both reference the same memory segement without copying it.
class DataContainer;
public:
// The "Segment" class represent a countinuous part of the buffer. Unlike the "DataContainer" class, it is not
// shared between diffrent buffers. It can be thought of as shared pointer to the "DataContainer" class - but it
// also has additional capabilities of scoping, compairson, and handling copying-in of the memory.
class Segment;
// The "SegIterator" class allow iterating over the different segments of the buffer (for specifc part of the code
// that require very high performance). The "SegRange" class is used for the `for ( : )` syntax.
using SegIterator = std::vector<Segment>::const_iterator;
class SegRange final
{
public:
SegIterator begin() { return b; }
SegIterator end() { return e; }
private:
friend class Buffer;
SegRange(const SegIterator &_b, const SegIterator &_e) : b(_b), e(_e) {}
SegIterator b, e;
};
// The "CharIterator" class is used to access the buffer, and may become invalid if the buffer changes.
// The "InternalPtr" class is used to read from the buffer through a structure, and is garantied to hold its
// original value even after the buffer changes or deleted.
class CharIterator;
template <typename T> class InternalPtr;
public:
using value_type = u_char;
using const_iterator = CharIterator;
Buffer() {}
Buffer(std::vector<u_char> &&vec);
Buffer(const std::vector<u_char> &vec);
Buffer(const std::vector<char> &vec);
Buffer(const std::string &str);
Buffer(const u_char *_ptr, uint _len, MemoryType type);
Buffer(const char *_ptr, uint _len, MemoryType type);
Buffer(const Buffer &);
Buffer(Buffer &&);
Buffer & operator=(const Buffer &);
Buffer & operator=(Buffer &&);
static void preload(); // Adds buffer evaluators
static void init() {}
static void fini() {}
static std::string getName() { return "Buffer"; }
uint size() const { return len; }
bool isEmpty() const { return len==0; }
bool contains(char ch) const;
uint segmentsNumber() const;
void operator+=(const Buffer &);
Buffer operator+(const Buffer &) const;
Buffer getSubBuffer(uint start, uint end) const;
Maybe<uint> findFirstOf(char ch, uint start = 0) const;
Maybe<uint> findFirstOf(const Buffer &buf, uint start = 0) const;
Maybe<uint> findFirstNotOf(char ch, uint start = 0) const;
Maybe<uint> findLastOf(char ch) const { return findLastOf(ch, len); }
Maybe<uint> findLastOf(char ch, uint start) const;
Maybe<uint> findLastNotOf(char ch) const { return findLastNotOf(ch, len); }
Maybe<uint> findLastNotOf(char ch, uint start) const;
void truncateHead(uint size);
void truncateTail(uint size);
void keepHead(uint size);
void keepTail(uint size);
void clear();
bool operator==(const Buffer &buf) const;
bool operator!=(const Buffer &buf) const { return !((*this)==buf); }
bool isEqual(const u_char *ptr, uint size) const;
bool isEqual(const char *ptr, uint size) const { return isEqual(reinterpret_cast<const u_char *>(ptr), size); }
bool isEqualLowerCase(const Buffer &buf) const;
bool operator<(const Buffer &buf) const;
bool operator<=(const Buffer &buf) const { return !(buf < *this); }
bool operator>(const Buffer& buf) const { return (buf < *this); }
bool operator>=(const Buffer &buf) const { return !(*this < buf); }
const u_char * data() const { serialize(); return fast_path_ptr; }
Maybe<InternalPtr<u_char>> getPtr(uint start, uint len) const;
template <typename T> Maybe<InternalPtr<T>> getTypePtr(uint start) const;
const u_char & operator[](uint offset) const;
operator std::string() const;
CharIterator begin() const;
CharIterator end() const;
SegRange segRange() const;
void serialize() const;
template<class Archive> void save(Archive &ar, uint32_t) const;
template<class Archive> void load(Archive &ar, uint32_t);
private:
void evalFastPath() const;
std::vector<Segment> segs;
uint len = 0;
// The "fast_path_ptr" and "fast_path_len" are used to allow a direct fast access to the beginning of the buffer
// (the first segment), which is the typical case.
uint fast_path_len = 0;
const u_char *fast_path_ptr = nullptr;
// The "type" and "is_owned" are used to make sure that the "fast_path_ptr" is up-to-date (regarding copying-in).
Volatility type = Volatility::NONE;
bool *is_owned = nullptr;
};
#include "buffer/data_container.h"
#include "buffer/segment.h"
#include "buffer/char_iterator.h"
#include "buffer/internal_ptr.h"
template<typename T>
Maybe<Buffer::InternalPtr<T>>
Buffer::getTypePtr(uint start) const
{
auto ptr = getPtr(start, sizeof(T));
if (!ptr.ok()) return ptr.passErr();
return InternalPtr<T>(ptr.unpackMove());
}
template<class Archive>
void
Buffer::save(Archive &ar, uint32_t) const
{
ar(segs, len);
}
template<class Archive>
void
Buffer::load(Archive &ar, uint32_t)
{
ar(segs, len);
evalFastPath();
}
#include "buffer/helper_functions.h"
#endif // __BUFFER_H__

View File

@@ -0,0 +1,53 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __BUFFER_CHAR_ITERATOR_H__
#define __BUFFER_CHAR_ITERATOR_H__
#include <iterator>
class Buffer::CharIterator
{
public:
using value_type = u_char;
CharIterator() {}
void operator++();
void operator++(int) { ++(*this); }
void operator+=(uint);
CharIterator operator+(uint) const;
bool operator==(const CharIterator &other) const;
bool operator!=(const CharIterator &other) const { return !((*this)==other); }
const u_char & operator*() const;
private:
friend class Buffer;
CharIterator(const SegIterator &_cur, const SegIterator &_end, uint _offset);
CharIterator(const SegIterator &_end);
SegIterator cur_seg, end_seg;
const u_char *ptr = nullptr;
uint offset = 0, size = 0;
};
namespace std
{
template <>
struct iterator_traits<Buffer::CharIterator>
{
using value_type = u_char;
};
}; // namespace std
#endif // __BUFFER_CHAR_ITERATOR_H__

View File

@@ -0,0 +1,71 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __BUFFER_DATA_CONTAINER_H__
#define __BUFFER_DATA_CONTAINER_H__
class Buffer::DataContainer
{
public:
DataContainer() : ptr(nullptr), len(0) {}
DataContainer(std::vector<u_char> &&_vec);
DataContainer(const u_char *_ptr, uint _len, MemoryType _type);
DataContainer(const DataContainer &) = delete;
DataContainer(DataContainer &&) = delete;
const u_char * data() const { return ptr; }
uint size() const { return len; }
// The "checkOnwership" method returns the place where the current memory type is owned by the I/S.
// This makes it possible to check if the memory has been moved (from VOLATILE to ONWED).
bool * checkOnwership() { return &is_owned; }
void
takeOwnership()
{
vec = std::vector<u_char>(ptr, ptr + len);
ptr = vec.data();
is_owned = true;
}
template<class Archive>
void
save(Archive &ar, uint32_t) const
{
if (is_owned) {
ar(vec);
} else {
std::vector<u_char> data(ptr, ptr + len);
ar(data);
}
}
template<class Archive>
void
load(Archive &ar, uint32_t)
{
ar(vec);
is_owned = true;
ptr = vec.data();
len = vec.size();
}
private:
// If the memory is OWNED (not STATIC or VOLATILE), the "vec" member is holding it - otherwise it is empty.
std::vector<u_char> vec;
// The "ptr" member points to the the beginning of the data, regardless of the type of memory.
const u_char *ptr = nullptr;
uint len = 0;
bool is_owned = true;
};
#endif // __BUFFER_DATA_CONTAINER_H__

View File

@@ -0,0 +1,46 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __BUFFER_HELPER_FUNCTIONS_H__
#define __BUFFER_HELPER_FUNCTIONS_H__
// Function to allow comparison with types that have data (of types char or u_char) and size
template <typename T>
bool
operator==(const Buffer &buf, const T &t)
{
return buf.isEqual(t.data(), t.size());
}
template <typename T>
bool
operator==(const T &t, const Buffer &buf)
{
return buf.isEqual(t.data(), t.size());
}
template <typename T>
bool
operator!=(const Buffer &buf, const T &t)
{
return !buf.isEqual(t.data(), t.size());
}
template <typename T>
bool
operator!=(const T &t, const Buffer &buf)
{
return !buf.isEqual(t.data(), t.size());
}
#endif // __BUFFER_HELPER_FUNCTIONS_H__

View File

@@ -0,0 +1,53 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __BUFFER_INTERNAL_PTR_H__
#define __BUFFER_INTERNAL_PTR_H__
template <typename T>
class Buffer::InternalPtr
{
public:
InternalPtr(const InternalPtr &) = default;
InternalPtr(InternalPtr &&o) : ptr(o.ptr), ref(std::move(o.ref)) { o.ptr = nullptr; }
InternalPtr & operator=(const InternalPtr &) = default;
InternalPtr &
operator=(InternalPtr &&o)
{
ptr = o.ptr;
ref = std::move(o.ref);
o.ptr = nullptr;
return *this;
}
operator const T *() const { return ptr; }
const T & operator*() const { dbgAssert(ptr != nullptr) << "Accessing a moved pointer"; return *ptr; }
const T * operator->() const { return ptr; }
private:
friend class Buffer;
InternalPtr(const T *_ptr, const std::shared_ptr<DataContainer> &data) : ptr(_ptr), ref(data) {}
template<typename O>
InternalPtr(InternalPtr<O> &&other)
:
ptr(reinterpret_cast<const T *>(other.ptr)),
ref(std::move(other.ref))
{}
const T *ptr;
std::shared_ptr<DataContainer> ref;
};
#endif // __BUFFER_INTERNAL_PTR_H__

View File

@@ -0,0 +1,75 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __BUFFER_SEGMENT_H__
#define __BUFFER_SEGMENT_H__
class Buffer::Segment
{
public:
Segment() {}
Segment(std::vector<u_char> &&_vec);
Segment(const u_char *_ptr, uint _len, MemoryType _type);
~Segment();
Segment(const Segment &);
Segment(Segment &&);
Segment & operator=(const Segment &);
Segment & operator=(Segment &&);
const u_char * data() const;
uint size() const { return len; }
template<class Archive>
void
save(Archive &ar, uint32_t) const
{
ar(data_container, offset, len);
}
template<class Archive>
void
load(Archive &ar, uint32_t)
{
// In the usual case, the `load` method is called on a newly default constructed object.
// However, since there is no guarantee that will always be the case, we need to make sure to handle the case
// where the object the data is loaded to is currently used as a PRIMARY.
if (type==Volatility::PRIMARY && !data_container.unique()) {
data_container->takeOwnership();
}
ar(data_container, offset, len);
type = Volatility::NONE;
is_owned = nullptr;
ptr = data_container->data() + offset;
}
private:
friend class Buffer;
// The "data_container" is the smart pointer to the actual memory.
std::shared_ptr<DataContainer> data_container;
// The "offset" and "len" members are used to indicate what part of the shared memory the segment refers to.
uint offset = 0, len = 0;
// The "type" member holds the volatility status of the memory.
Volatility type = Volatility::NONE;
// The "is_owned" member is used in case of SECONDARY volatility to check if ownership of the memory was taken.
// It a pointer to `data_container->is_owned` if the segement is SECONDARY, and nullptr if it isn't.
bool *is_owned = nullptr;
// The "ptr" member is used to gain access to the memory directly without going to through the shared memory
// pointer (fast path).
const u_char *ptr = nullptr;
};
#endif // __BUFFER_SEGMENT_H__

View File

@@ -0,0 +1,55 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __IP_COMMON_C__
#define __IP_COMMON_C__
enum IpVersion {
IP_VERSION_ANY = 0,
IP_VERSION_4 = 4,
IP_VERSION_6 = 6,
};
typedef enum IpVersion IpVersion;
typedef struct IpAddress {
union {
struct in_addr ipv4;
struct in6_addr ipv6;
} ip;
#define addr4_t ip.ipv4
#define addr6_t ip.ipv6
IpVersion ip_type;
} IpAddress;
typedef struct IPRange {
IpAddress start;
IpAddress end;
} IPRange;
typedef struct PortsRange {
uint16_t start;
uint16_t end;
} PortsRange;
typedef struct IpProtoRange {
uint8_t start;
uint8_t end;
} IpProtoRange;
typedef struct GDFilter {
IPRange *source;
unsigned int size;
} GDFilter;
#endif // __IP_COMMON_C__

View File

@@ -0,0 +1,265 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __NETWORK_DEFS__
#define __NETWORK_DEFS__
// Various network layer definitions
// Note: we get Linux's annyoing TCP headers, not BSD's nicer ones.
// A significant difference is that TCP flags are bit fields, so masking is hard.
// Maybe we should just copy&paste nice headers and be more portable?
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#ifndef alpine
#include <bits/endian.h>
#else
#include <endian.h>
#endif
// Sometimes BSD's flag definitions are just so much more convenient.
// So let people use them.
// XXX: Very ugly. Better really switch to BSD.
#ifdef __cplusplus
using TCPFlags = u_char;
#else
typedef u_char TCPFlags;
#endif
#ifndef TH_FIN
static const u_char TH_FIN=0x01;
#endif
#ifndef TH_SYN
static const u_char TH_SYN=0x02;
#endif
#ifndef TH_RST
static const u_char TH_RST=0x04;
#endif
#ifndef TH_PSH
static const u_char TH_PSH=0x08;
#endif
#ifndef TH_ACK
static const u_char TH_ACK=0x10;
#endif
#ifndef TH_URG
static const u_char TH_URG=0x20;
#endif
// Linux TCP headers are not the same for all distros, so we bring tcp/udp structs here
// probably switch to BSD headers is a better options
struct UdpHdr
{
uint16_t source;
uint16_t dest;
uint16_t len;
uint16_t check;
};
struct TcpHdr
{
uint16_t source;
uint16_t dest;
uint32_t seq;
uint32_t ack_seq;
# if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t res1:4;
uint8_t doff:4;
union {
struct {
uint8_t fin:1;
uint8_t syn:1;
uint8_t rst:1;
uint8_t psh:1;
uint8_t ack:1;
uint8_t urg:1;
uint8_t res2:2;
};
uint8_t flags;
};
# elif __BYTE_ORDER == __BIG_ENDIAN
uint8_t doff:4;
uint8_t res1:4;
union {
struct {
uint8_t res2:2;
uint8_t urg:1;
uint8_t ack:1;
uint8_t psh:1;
uint8_t rst:1;
uint8_t syn:1;
uint8_t fin:1;
};
uint8_t flags;
};
#else
# error "Adjust your <bits/endian.h> defines"
#endif
uint16_t window;
uint16_t check;
uint16_t urg_ptr;
};
#ifndef IPPROTO_MH
#define IPPROTO_MH 135
#endif
// GRE START
#ifndef GREPROTO_PPP
#define GREPROTO_PPP 0x880B
#endif
struct GreHdr
{
uint16_t flags;
uint16_t proto_type;
};
struct EnhancedGreHdr
{
uint16_t flags;
uint16_t proto_type;
uint16_t data_length;
uint16_t call_id;
};
// GRE END
// SCTP START
struct SctpHdr
{
uint16_t sport;
uint16_t dport;
uint vtag;
uint sum;
};
struct SctpChunkHdr
{
u_char chunk_type;
u_char chunk_flags;
uint16_t chunk_length;
};
// SCTP END
// DCCP START
#ifndef DCCPO_CHANGE_L
#define DCCPO_CHANGE_L 32
#endif
#ifndef DCCPO_CHANGE_R
#define DCCPO_CHANGE_R 34
#endif
struct DccpHdr
{
uint16_t dccph_sport;
uint16_t dccph_dport;
u_char dccph_doff;
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_char dccph_cscov : 4,
dccph_ccval : 4;
#elif __BYTE_ORDER == __BIG_ENDIAN
u_char dccph_ccval : 4,
dccph_cscov : 4;
#else
#error unknown byte order
#endif // __BYTE_ORDER
uint16_t dccph_checksum;
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_char dccph_x : 1,
dccph_type : 4,
dccph_reserved : 3;
#elif __BYTE_ORDER == __BIG_ENDIAN
u_char dccph_reserved : 3,
dccph_type : 4,
dccph_x : 1;
#else
#error unknown byte order
#endif // __BYTE_ORDER
u_char dccph_seq2;
uint16_t dccph_seq;
};
struct DccpHdrExt
{
uint dccph_seq_low;
};
struct DccpOptHdr
{
u_char type;
u_char length;
};
struct DccpHdrAckBits
{
uint16_t dccph_reserved1;
uint16_t dccph_ack_nr_high;
uint dccph_ack_nr_low;
};
struct DccpHdrRequest
{
uint dccph_req_service;
};
struct DccpHdrResponse
{
struct DccpHdrAckBits dccph_resp_ack;
uint dccph_resp_service;
};
struct DccpHdrReset
{
struct DccpHdrAckBits dccph_reset_ack;
uint16_t dccph_reset_code;
uint16_t dccph_reset_data[3];
};
enum DccpPacketType {
DCCP_PKT_REQUEST = 0,
DCCP_PKT_RESPONSE,
DCCP_PKT_DATA,
DCCP_PKT_ACK,
DCCP_PKT_DATAACK,
DCCP_PKT_CLOSEREQ,
DCCP_PKT_CLOSE,
DCCP_PKT_RESET,
DCCP_PKT_SYNC,
DCCP_PKT_SYNCACK,
DCCP_PKT_INVALID,
};
// DCCP END
static inline TCPFlags
getTCPFlags(const struct TcpHdr *tcp)
{
TCPFlags res = (TCPFlags)0;
if (tcp->fin) res |= TH_FIN;
if (tcp->syn) res |= TH_SYN;
if (tcp->rst) res |= TH_RST;
if (tcp->psh) res |= TH_PSH;
if (tcp->ack) res |= TH_ACK;
if (tcp->urg) res |= TH_URG;
return res;
}
#endif // __NETWORK_DEFS__

View File

@@ -0,0 +1,211 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __NETWORKING_HEADERS_H__
#define __NETWORKING_HEADERS_H__
#define ETH_P_IPV6 0x86DD
#define ETH_P_IP 0x0800
#define NF_DROP 0u
#define NF_ACCEPT 1u
#ifndef DCCPO_CHANGE_L
#define DCCPO_CHANGE_L 32
#endif
#ifndef DCCPO_CHANGE_R
#define DCCPO_CHANGE_R 34
#endif
typedef unsigned int sk_buff_data_t;
enum PROTOCOL {
ICMP = 1, //0x1
TCP = 6, //0x6
UDP = 17, //0x11
DCCP = 33, //0x21
IPV6_FRAG = 44, //0x2c
ICMPV6 = 58, //0x3A
SCTP = 132 //0x84
};
enum DccpPacketType {
DCCP_PKT_REQUEST = 0,
DCCP_PKT_RESPONSE,
DCCP_PKT_DATA,
DCCP_PKT_ACK,
DCCP_PKT_DATAACK,
DCCP_PKT_CLOSEREQ,
DCCP_PKT_CLOSE,
DCCP_PKT_RESET,
DCCP_PKT_SYNC,
DCCP_PKT_SYNCACK,
DCCP_PKT_INVALID,
};
struct sk_buff {
uint16_t protocol;
union {
struct iphdr *ip_header;
struct ipv6hdr *ipv6_header;
} network_header;
union {
struct udphdr *udp_header;
struct tcphdr *tcp_header;
struct icmphdr *icmp_header;
struct icmp6hdr *icmp6_header;
struct sctphdr *sctp_header;
struct dccphdr *dccp_header;
} transport_header;
unsigned char *tail;
unsigned char *data;
unsigned char *head;
unsigned int len;
};
struct geneve_opt {
__u16 opt_class;
u_int8_t type;
#ifdef __LITTLE_ENDIAN_BITFIELD
u_int8_t length:5;
u_int8_t r3:1;
u_int8_t r2:1;
u_int8_t r1:1;
#else
u_int8_t r1:1;
u_int8_t r2:1;
u_int8_t r3:1;
u_int8_t length:5;
#endif
u_int8_t opt_data[];
};
struct genevehdr {
#ifdef __LITTLE_ENDIAN_BITFIELD
u_int8_t opt_len:6;
u_int8_t ver:2;
u_int8_t rsvd1:6;
u_int8_t critical:1;
u_int8_t oam:1;
#else
u_int8_t ver:2;
u_int8_t opt_len:6;
u_int8_t oam:1;
u_int8_t critical:1;
u_int8_t rsvd1:6;
#endif
__u16 proto_type;
u_int8_t vni[3];
u_int8_t rsvd2;
struct geneve_opt options[];
};
struct sctphdr {
u_int16_t source;
u_int16_t dest;
u_int32_t vtag;
u_int32_t checksum;
};
struct ipv6hdr {
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t priority : 4,
version : 4;
#elif __BYTE_ORDER == __BIG_ENDIAN
u_int8_t version : 4,
priority : 4;
#else
#error unknown byte order
#endif // __BYTE_ORDER
u_int8_t flow_lbl[3];
u_int16_t payload_len;
u_int8_t nexthdr;
u_int8_t hop_limit;
struct in6_addr saddr;
struct in6_addr daddr;
};
struct dccp_hdr
{
uint16_t dccph_sport;
uint16_t dccph_dport;
u_char dccph_doff;
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_char dccph_cscov : 4,
dccph_ccval : 4;
#elif __BYTE_ORDER == __BIG_ENDIAN
u_char dccph_ccval : 4,
dccph_cscov : 4;
#else
#error unknown byte order
#endif // __BYTE_ORDER
uint16_t dccph_checksum;
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_char dccph_x : 1,
dccph_type : 4,
dccph_reserved : 3;
#elif __BYTE_ORDER == __BIG_ENDIAN
u_char dccph_reserved : 3,
dccph_type : 4,
dccph_x : 1;
#else
#error unknown byte order
#endif // __BYTE_ORDER
u_char dccph_seq2;
uint16_t dccph_seq;
};
struct sctp_chunkhdr
{
u_char chunk_type;
u_char chunk_flags;
uint16_t chunk_length;
};
struct dccp_hdr_ext
{
uint dccph_seq_low;
};
struct dccp_hdr_request
{
uint dccph_req_service;
};
struct dccp_opt_hdr
{
u_char type;
u_char length;
};
struct dccp_hdr_ack_bits
{
uint16_t dccph_reserved1;
uint16_t dccph_ack_nr_high;
uint dccph_ack_nr_low;
};
struct dccp_hdr_response
{
struct dccp_hdr_ack_bits dccph_resp_ack;
uint dccph_resp_service;
};
struct dccp_hdr_reset
{
struct dccp_hdr_ack_bits dccph_reset_ack;
uint16_t dccph_reset_code;
uint16_t dccph_reset_data[3];
};
#endif // __NETWORKING_HEADERS_H__

View File

@@ -0,0 +1,138 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __COMMON_H__
#define __COMMON_H__
#define CP_LIKELY(cond) __builtin_expect((bool)(cond), 1)
#define CP_UNLIKELY(cond) __builtin_expect((bool)(cond), 0)
#define CP_UNUSED __attribute__((unused))
#define CP_NO_RETURN __attribute__((noreturn))
#if defined(__GNUC__) && __GNUC__ >= 7
#define CP_FALL_THROUGH __attribute__ ((fallthrough))
#else
#define CP_FALL_THROUGH ((void)0)
#endif // __GNUC__ >= 7
#include <memory>
#include <string>
#include <sstream>
#include <iomanip>
#include <sys/types.h>
namespace std
{
#if __cplusplus < 201402L
// make_unique isn't part of C++11 - but pretty useful, so we'll define it in such cases
template<typename ConstructedType, typename... Args>
unique_ptr<ConstructedType>
make_unique(Args&&... args)
{
return unique_ptr<ConstructedType>(new ConstructedType(forward<Args>(args)...));
}
#endif // __cplusplus < 201402L
// Not part of the C++11 standard, but is useful imitation of Python's `join`
template <typename Iterable>
string
makeSeparatedStr(const Iterable &data, const string &separator)
{
ostringstream os;
bool not_first = false;
for (const auto &element : data) {
if (not_first) os << separator;
os << element;
not_first = true;
}
return os.str();
}
template <typename Char>
string
dumpHexChar(const Char &ch)
{
ostringstream stream;
if (isprint(ch) && (!isspace(ch) || ch==' ')) {
stream << "'" << ch << "'";
} else {
stream << "\\x" << setw(2) << setfill('0') << hex << static_cast<int>(ch);
}
return stream.str();
}
// Produce a hex string from some container of charecters.
// The container must be iterable.
template <typename CharIterable>
string
dumpHex(const CharIterable &arg)
{
ostringstream stream;
stream << hex;
for (uint8_t ch : arg) {
if (isprint(ch) && (!isspace(ch) || ch==' ')) {
// Printable characters, except for whitespaces which aren't space.
if (ch == '\\') stream << '\\';
stream << ch;
} else {
stream << "\\x" << setw(2) << setfill('0') << static_cast<int>(ch);
}
}
return stream.str();
}
template <typename CharIterable>
string
dumpRealHex(const CharIterable &arg)
{
ostringstream stream;
stream << hex;
for (uint8_t ch : arg) {
stream << " " << setw(2) << setfill('0') << static_cast<int>(ch);
}
return stream.str();
}
template <typename T, typename Helper = void>
struct IsPrintable : false_type
{
};
template <typename T>
struct IsPrintable<T, decltype(static_cast<void>(declval<ostream &>() << declval<T>()))> : true_type
{
};
template <typename CanPrint>
ostream &
operator<<(ostream &os, const decltype(declval<CanPrint>().print(declval<ostream &>()), declval<CanPrint>()) &obj)
{
obj.print(os);
return os;
}
template <typename First, typename Second>
ostream&
operator<<(ostream &os, const pair<const First, Second> &printable_pair)
{
os << "{" << printable_pair.first << "," << printable_pair.second << "}";
return os;
}
} // namespace std
#endif // __COMMON_H__

View File

@@ -0,0 +1,56 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __CONFIG_COMPONENT_H__
#define __CONFIG_COMPONENT_H__
#include <string>
#include <vector>
#include "config.h"
#include "singleton.h"
#include "i_rest_api.h"
#include "i_time_get.h"
#include "i_mainloop.h"
#include "i_environment.h"
#include "i_messaging.h"
#include "i_instance_awareness.h"
#include "i_tenant_manager.h"
#include "component.h"
class ConfigComponent
:
public Component,
Singleton::Provide<Config::I_Config>,
Singleton::Consume<I_RestApi>,
Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_Messaging>,
Singleton::Consume<I_InstanceAwareness>,
Singleton::Consume<I_TenantManager>
{
public:
ConfigComponent();
~ConfigComponent();
void preload();
void init();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __CONFIG_COMPONENT_H__

43
core/include/general/cptest.h Executable file
View File

@@ -0,0 +1,43 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#if !defined(__CP_TEST_H__)
#define __CP_TEST_H__
//
// CP definitions which are useful in many unit tests
//
#include <string>
#include <vector>
#include <ostream>
#include <functional>
#include "cptest/cptest_basic.h"
#include "cptest/cptest_file.h"
#include "cptest/cptest_singleton.h"
#include "cptest/cptest_maybe.h"
#include "buffer.h"
#include "scope_exit.h"
#include "tostring.h"
std::ostream& operator<<(std::ostream &os, const Buffer &buf);
// Parse a hex string, e.g. the output of tcpdump -xx, into a vector.
std::vector<u_char> cptestParseHex(const std::string &hex_text);
// The inverse of cptest_parse_hex
// Take a vector of data, and generate hex from it output, like tcpdump.
std::string cptestGenerateHex(const std::vector<u_char> &vec, bool print_offsets);
#endif // __CP_TEST_H__

View File

@@ -0,0 +1,36 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __CP_TEST_BASIC_H__
#define __CP_TEST_BASIC_H__
#include "gtest/gtest.h"
#include "gmock/gmock.h"
// Before EXPECT_DEATH, call this to do all necessary preparations.
void cptestPrepareToDie();
// Path to a file in the UT directory
std::string cptestFnameInExeDir(const std::string &name);
std::string cptestFnameInSrcDir(const std::string &name);
ACTION_TEMPLATE(
SaveVoidArgPointee,
HAS_2_TEMPLATE_PARAMS(int, k, typename, T),
AND_1_VALUE_PARAMS(output)
)
{
*output = *static_cast<T *>(::testing::get<k>(args));
}
#endif // __CP_TEST_BASIC_H__

View File

@@ -0,0 +1,37 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __CPTEST_FILE_H__
#define __CPTEST_FILE_H__
// Create a temporary file with some content. Delete on destruction.
class CPTestTempfile
{
public:
explicit CPTestTempfile(const std::vector<std::string> &lines);
explicit CPTestTempfile();
~CPTestTempfile();
std::string readFile() const;
std::string fname;
// Not copiable (would delete the file twice), but movable
CPTestTempfile(const CPTestTempfile &other) = delete;
CPTestTempfile(CPTestTempfile &&other) = default;
CPTestTempfile & operator=(const CPTestTempfile &other) = delete;
CPTestTempfile & operator=(CPTestTempfile &&other) = default;
};
#endif // __CPTEST_FILE_H__

View File

@@ -0,0 +1,164 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __CPTEST_MAYBE_H__
#define __CPTEST_MAYBE_H__
#include "maybe_res.h"
#include "gmock/gmock.h"
namespace testing {
namespace maybe_matcher {
// Matchers for Maybe<T> objects.
// Usage examples:
// Maybe<int> m = ...;
// EXPECT_THAT(m, IsValue(3)); // Must hold 3
// EXPECT_THAT(m, IsValue(_)); // Must be a value
// EXPECT_THAT(m, IsError("HA")); // Must be an error with specific text
// EXPECT_THAT(m, IsError(_)); // Any error (but not a value)
//
// Generic classes that handle either the value or the error
//
// Matcher for Maybe values.
// Verify that Maybe<T>::ok() is as expected, and runs a matcher on the internal value or error.
//
// Abstract base class, inherited to match either the internal value or the error value.
// Template parameters:
// MaybeType - the Maybe type, possibly with "const &".
// GetInternal - gets the internal value or error from Maybe.
template <typename MaybeType, typename GetInternal>
class BaseMatcher : public MatcherInterface<MaybeType>
{
private:
using InternalValue = decltype(GetInternal::get(std::declval<MaybeType>()));
public:
BaseMatcher(const Matcher<InternalValue> &_matcher)
:
label(GetInternal::expected_ok ? "Value" : "Error"),
matcher(_matcher)
{
}
bool
MatchAndExplain(MaybeType m, MatchResultListener *listener) const override {
if (m.ok() != GetInternal::expected_ok) return false;
return matcher.MatchAndExplain(GetInternal::get(m), listener);
}
// LCOV_EXCL_START - Only called when a test fails, to explain why.
void
DescribeTo(::std::ostream *os) const override {
*os << label << "(";
matcher.DescribeTo(os);
*os << ")";
}
void
DescribeNegationTo(::std::ostream *os) const override {
*os << label << "(";
matcher.DescribeNegationTo(os);
*os << ")";
}
// LCOV_EXCL_STOP
private:
std::string label;
Matcher<InternalValue> matcher;
};
// Temporary matcher for Maybe values - converted to BaseMatcher when needed.
// Converts any matcher to a Maybe matcher, which invokes the internal matcher on the value or error.
// Template parameters:
// InternalMatcherType - Any matcher type that matches the value/error.
// InternalValueGetter - gets the internal value or error from Maybe.
template <typename InternalMatcherType, typename InternalValueGetter>
class TempMatcher
{
public:
TempMatcher(InternalMatcherType _matcher) : matcher(_matcher) {}
// The internal type becomes known when this object is cast to a specific
// matcher type. Create a Maybe matcher, while casting the internal matcher to the
// type that we now know.
template <typename MaybeType>
operator Matcher<MaybeType>() const
{
using MaybeMatcherType = BaseMatcher<MaybeType, InternalValueGetter>;
return MakeMatcher(new MaybeMatcherType(matcher));
}
private:
InternalMatcherType matcher;
};
//
// Classes to get the internal value from a Maybe object.
// The internal value can be either the value or the error.
//
class GetValue
{
public:
static const bool expected_ok = true;
template<typename T, typename TErr>
static T
get(const Maybe<T, TErr> &m)
{
return m.unpack();
}
};
class GetError
{
public:
static const bool expected_ok = false;
template<typename T, typename TErr>
static TErr
get(const Maybe<T, TErr> &m)
{
return m.getErr();
}
};
} // namespace maybe_matcher
//
// Functions to return matchers - to be used by test code.
//
// Convert Matcher<T> to Matcher<Maybe<T>>, which verifies that it's ok and matches the value.
template<typename MatcherType>
static inline ::testing::maybe_matcher::TempMatcher<MatcherType, ::testing::maybe_matcher::GetValue>
IsValue(MatcherType matcher)
{
return ::testing::maybe_matcher::TempMatcher<MatcherType, ::testing::maybe_matcher::GetValue>(matcher);
}
// Convert Matcher<TErr> to Matcher<Maybe<T, TErr>>, which verifies that it's not ok and matches the error.
template<typename MatcherType>
static inline ::testing::maybe_matcher::TempMatcher<MatcherType, ::testing::maybe_matcher::GetError>
IsError(MatcherType matcher)
{
return ::testing::maybe_matcher::TempMatcher<MatcherType, ::testing::maybe_matcher::GetError>(matcher);
}
} // namespace testing
#endif // __CPTEST_MAYBE_H__

View File

@@ -0,0 +1,27 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __CP_TEST_SINGLETON_H__
#define __CP_TEST_SINGLETON_H__
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "singleton.h"
// Mock objects should use Singleton::Provide<I_Face>::From<MockProvider> with the interface they mock.
template<typename I_Face>
class MockProvider : Singleton::Provide<I_Face>
{};
#endif // __CP_TEST_SINGLETON_H__

View File

@@ -0,0 +1,88 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __CPTEST_TCPPACKET_H__
#define __CPTEST_TCPPACKET_H__
#include <vector>
#include <string>
#include <memory>
#include "packet.h"
// Generate TCP options
class TCPOption
{
public:
explicit TCPOption(const std::string &_name, const std::vector<u_char> _data);
TCPOption(const TCPOption &from);
~TCPOption();
// Accessors
size_t size() const;
std::vector<u_char> build() const;
// Well-known options - simple ones are constants, complex are are static functions
static const TCPOption NOP;
static const TCPOption SACK_PERMITTED;
static TCPOption windowScaling(u_char shift_count);
static TCPOption timeStamp(uint value, uint echo_reply);
static TCPOption selectiveACK(const std::vector<std::pair<uint, uint>> &edges);
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
class TCPPacket
{
public:
// Build an empty packet
explicit TCPPacket(CDir _cdir);
~TCPPacket();
// Movable, not copiable
TCPPacket(TCPPacket &&from);
TCPPacket(const TCPPacket &from) = delete;
// Methods to set TCP properties. Return reference to this, to allow chaining
TCPPacket & setTCPPayload(const std::vector<u_char> &payload);
TCPPacket & setTCPPayload(const std::string &payload);
TCPPacket & setTCPSeq(uint _tcp_seq);
TCPPacket & setTCPAck(uint _tcp_ack);
TCPPacket & setTCPWindow(uint16_t _tcp_window);
TCPPacket & setTCPFlags(std::string _tcp_flags);
TCPPacket & setTCPUrgentPtr(uint16_t _tcp_urgent_ptr);
TCPPacket & setTCPCksum(uint _tcp_cksum_override);
TCPPacket & setL2Header(const std::vector<u_char> &_l2_header);
TCPPacket & addTCPOption(const TCPOption &tcp_option);
TCPPacket & setL4HeaderSize(uint header_size);
TCPPacket & setL4DataOffset(uint data_offset);
TCPPacket && move() { return std::move(*this); }
// Build a Packet
std::unique_ptr<Packet> build(const ConnKey &ck) const;
// Get the TCP sequence
uint getTCPSeq() const;
static uint16_t calcTCPv4Checksum(const std::vector<u_char> &pkt);
static uint16_t calcTCPv6Checksum(const std::vector<u_char> &pkt);
static uint16_t calcIPv4Checksum(const std::vector<u_char> &pkt);
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __CPTEST_TCPPACKET_H__

269
core/include/general/debug.h Executable file
View File

@@ -0,0 +1,269 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include <set>
#include <functional>
#include <chrono>
#include <vector>
#include "common.h"
#include "singleton.h"
#include "scope_exit.h"
class I_TimeGet;
class I_Messaging;
class I_MainLoop;
class I_Environment;
class I_InstanceAwareness;
class I_Encryptor;
class I_AgentDetails;
class I_SignalHandler;
class Debug
:
Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_Messaging>,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_InstanceAwareness>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_Encryptor>,
Singleton::Consume<I_AgentDetails>,
Singleton::Consume<I_SignalHandler>
{
public:
class DebugStream;
enum class DebugLevel { NOISE, TRACE, DEBUG, INFO, WARNING, ERROR, ASSERTION, NONE };
enum class DebugFlags;
class DebugStreamAggr
{
template <typename T, typename Helper = void>
struct Print
{
Print(std::ostream *str, const T &obj) { (*str) << obj; }
};
template <typename T>
struct Print<T, decltype(std::declval<T>().print(std::declval<std::ostream &>()))>
{
Print(std::ostream *str, const T &obj) { obj.print(*str); }
};
public:
template <typename T>
DebugStreamAggr &
operator<<(const T &obj)
{
for (auto &stream : streams) {
Print<T>(stream, obj);
}
return *this;
}
DebugStreamAggr &
operator<<(std::ostream & (*func)(std::ostream &))
{
for (auto &stream : streams) {
func(*stream);
}
return *this;
}
void addStream(std::ostream *stream) { streams.insert(stream); }
private:
std::set<std::ostream *> streams;
};
class DebugLockState
{
private:
friend class Environment;
static bool getState() { return is_debug_running; }
static void setState(const bool _is_debug_running) { is_debug_running = _is_debug_running; }
};
public:
Debug(
const std::string &file_name,
const std::string &func_name,
const uint &line
);
Debug(
const std::string &file_name,
const std::string &func_name,
const uint &line,
const DebugLevel &level,
const DebugFlags &flag1
);
Debug(
const std::string &file_name,
const std::string &func_name,
const uint &line,
const DebugLevel &level,
const DebugFlags &flag1,
const DebugFlags &flag2
);
Debug(
const std::string &file_name,
const std::string &func_name,
const uint &line,
const DebugLevel &level,
const DebugFlags &flag1,
const DebugFlags &flag2,
const DebugFlags &flag3
);
Debug(
const std::string &file_name,
const std::string &func_name,
const uint &line,
const DebugLevel &level,
const DebugFlags &flag1,
const DebugFlags &flag2,
const DebugFlags &flag3,
const DebugFlags &flag4
);
~Debug();
DebugStreamAggr &
getStreamAggr() __attribute__((warn_unused_result))
{
return stream;
}
static void preload();
static void init();
static void fini();
static std::string getName() { return "DebugIS"; }
static void prepareConfig();
static void commitConfig();
static void abortConfig();
static void failOpenDebugMode(std::chrono::seconds debug_period);
template <typename... Args>
static bool
evalFlags(DebugLevel level, DebugFlags flag, Args... args)
{
return !is_debug_running && level>=lowest_global_level && evalFlagByFlag(level, flag, args...);
}
static bool isFlagAtleastLevel(DebugFlags flag, DebugLevel level);
static void setNewDefaultStdout(std::ostream *new_stream);
static void setUnitTestFlag(DebugFlags flag, DebugLevel level);
static std::string findDebugFilePrefix(const std::string &file_name);
private:
template <typename T, typename... Args>
static bool
evalFlagByFlag(DebugLevel _level, T flag, Args... args)
{
return evalFlagByFlag(_level, flag) || evalFlagByFlag(_level, args...);
}
static bool evalFlagByFlag(DebugLevel _level, DebugFlags flag);
static bool evalFlagByFlag(DebugLevel) { return true; }
static void applyOverrides();
bool shouldApplyFailOpenOnStream(const std::string &name) const;
void addActiveStream(const std::string &name);
void printBacktraceBeforeAbort();
void startStreams(
const DebugLevel &level,
const std::string &file_name,
const std::string &func_name,
const uint &line
);
static DebugLevel lowest_global_level;
static I_TimeGet *time;
static I_MainLoop *mainloop;
static I_Environment *env;
static bool is_debug_running;
static bool is_fail_open_mode;
static bool debug_override_exist;
static std::string default_debug_file_stream_path;
static std::vector<std::string> streams_from_mgmt;
bool do_assert;
DebugStreamAggr stream;
std::set<std::shared_ptr<DebugStream>> current_active_streams;
};
#define USE_DEBUG_FLAG(x) extern const Debug::DebugFlags x
// This function extract the base name from a full path.
// The `iter` variable holds the current place of the iteration over the full path.
// The `base` variable holds where we currently think the base name starts
static inline constexpr const char *
getBaseName(const char *iter, const char *base)
{
// If `iter` doesn't point to the next charecter in the string, then return where we think the base name starts.
return (iter==nullptr || *iter=='\0') ? base :
// If `iter` points to '/' char, then now we thik the next char is the start of the base name, otherwise we
// stil think that `base` points to the start of the base name.
// In any case, we recursively progress `iter` to check the next char.
(*iter=='/' ? getBaseName(iter+1, iter+1) : getBaseName(iter+1, base));
}
#define __FILENAME__ getBaseName(__FILE__, __FILE__)
#define dbgAssert(cond) \
if (CP_LIKELY(cond)) { \
} else Debug(__FILENAME__, __FUNCTION__, __LINE__).getStreamAggr()
// Macros to allow simple debug messaging
#define DBG_GENERIC(level, ...) \
if (!Debug::evalFlags(Debug::DebugLevel::level, __VA_ARGS__)) { \
} else Debug(__FILENAME__, __FUNCTION__, __LINE__, Debug::DebugLevel::level, __VA_ARGS__).getStreamAggr()
#define isDebugRequired(level, flag) (Debug::evalFlags(Debug::DebugLevel::level, flag))
#define dbgTrace(...) DBG_GENERIC(TRACE, __VA_ARGS__)
#define dbgDebug(...) DBG_GENERIC(DEBUG, __VA_ARGS__)
#define dbgInfo(...) DBG_GENERIC(INFO, __VA_ARGS__)
#define dbgWarning(...) DBG_GENERIC(WARNING, __VA_ARGS__)
#define dbgError(...) DBG_GENERIC(ERROR, __VA_ARGS__)
// Macro for automatic printouts on entering and leaving scope
// Should be in the first line of a function
// Output is in Trace level
#define dbgFlow(...) \
auto __function_name = __FUNCTION__; \
auto __scope_exit = std::make_scope_exit( \
[__function_name] () { \
if (Debug::evalFlags(Debug::DebugLevel::TRACE, __VA_ARGS__)) { \
Debug(__FILENAME__, __function_name, __LINE__, Debug::DebugLevel::TRACE, __VA_ARGS__) \
.getStreamAggr() << "Exit"; \
} \
} \
); \
dbgTrace(__VA_ARGS__) << "Enter "
#endif // __DEBUG_H__

View File

@@ -0,0 +1,36 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ENCRYPTOR_H__
#define __ENCRYPTOR_H__
#include <memory>
#include "i_encryptor.h"
#include "singleton.h"
#include "component.h"
class Encryptor : public Component, Singleton::Provide<I_Encryptor>
{
public:
Encryptor();
~Encryptor();
void preload();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __ENCRYPTOR_H__

View File

@@ -0,0 +1,45 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ENVIRONMENT_H__
#define __ENVIRONMENT_H__
#include <memory>
#include "i_environment.h"
#include "i_tenant_manager.h"
#include "singleton.h"
#include "component.h"
class I_RestApi;
class Environment
:
public Component,
Singleton::Provide<I_Environment>,
Singleton::Consume<I_RestApi>,
Singleton::Consume<I_TenantManager>
{
public:
Environment();
~Environment();
void init();
void fini();
void preload();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __ENVIRONMENT_H__

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __HASH_COMBINE_H__
#define __HASH_COMBINE_H__
// Copied from Boost (hash_combine)
template <class T>
inline void hashCombine(size_t &seed, const T &v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
#endif // __HASH_COMBINE_H__

View File

@@ -0,0 +1,162 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __IMPL_SINGLETON_H__
#define __IMPL_SINGLETON_H__
#ifndef __SINGLETON_H__
#error impl/singleton.h should not be included directly.
#endif // SINGLETON_H__
template <class I_Face>
class Singleton::Provide
{
public:
template <class Comp>
class From : public I_Face
{
static_assert(
std::is_base_of<Provide<I_Face>, Comp>::value,
"Comp class must inherit from Singleton::Provide<I_Face>"
);
public:
From() { Singleton::registerSingleton(typeid(I_Face), this); }
~From() { Singleton::unregisterSingleton(typeid(I_Face), this); }
};
class Self;
class SelfInterface : Self, public I_Face
{
};
};
template <class I_Face>
class Singleton::Provide<I_Face>::Self : Provide<I_Face>
{
public:
Self() { Singleton::registerSingleton(typeid(I_Face), this); }
~Self() { Singleton::unregisterSingleton(typeid(I_Face), this); }
};
template <class I_Face>
class Singleton::Consume
{
public:
template <class ConsumingComp>
static inline I_Face *
by()
{
static_assert(
std::is_base_of<Consume<I_Face>, ConsumingComp>::value,
"ConsumingComp class must inherit from Singleton::Consume<I_Face>"
);
return get();
}
template <class ProvidingComp>
static inline I_Face *
from()
{
static_assert(
std::is_base_of<Provide<I_Face>, ProvidingComp>::value,
"ProvidingComp class must inherit from Singleton::Provide<I_Face>"
);
return get();
}
template <class ProvidingComp>
static inline I_Face *
from(const ProvidingComp &)
{
return from<ProvidingComp>();
}
template <class Comp>
static inline I_Face *
to()
{
static_assert(
std::is_base_of<Consume<I_Face>, Comp>::value || std::is_base_of<Provide<I_Face>, Comp>::value,
"Component class must declare it relationship to the interface"
);
return get();
}
private:
static inline I_Face * get() { return Singleton::get<I_Face>(); }
};
template <typename T>
bool
Singleton::exists()
{
return exists(typeid(T));
}
class Singleton::OwnedSingleton
{
public:
virtual ~OwnedSingleton() {}
};
template <typename T>
T *
Singleton::getOwned()
{
return static_cast<T *>(owned_singles[typeid(T)].get());
}
template <typename T>
bool
Singleton::existsOwned()
{
return owned_singles.count(typeid(T)) != 0;
}
template <typename T, typename ...Args>
void
Singleton::newOwned(Args ...args)
{
owned_singles[typeid(T)] = std::make_unique<T>(std::forward<Args>(args)...);
}
template <typename T>
void
Singleton::deleteOwned()
{
owned_singles.erase(typeid(T));
}
template <typename T>
void
Singleton::setOwned(std::unique_ptr<T> &&ptr)
{
owned_singles[typeid(T)] = std::move(ptr);
}
template <typename T>
T *
Singleton::get()
{
return static_cast<T *>(get(typeid(T)));
}
template <typename Component, typename Interface>
Interface *
getInterface()
{
return Singleton::Consume<Interface>::template to<Component>();
}
#endif // __IMPL_SINGLETON_H__

View File

@@ -0,0 +1,46 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __INTELLIGENCE_COMP_V2_H__
#define __INTELLIGENCE_COMP_V2_H__
#include "i_intelligence_is_v2.h"
#include "singleton.h"
#include "i_messaging.h"
#include "i_mainloop.h"
#include "i_time_get.h"
#include "component.h"
class IntelligenceComponentV2
:
public Component,
Singleton::Provide<I_Intelligence_IS_V2>,
Singleton::Consume<I_Messaging>,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_TimeGet>
{
public:
IntelligenceComponentV2();
~IntelligenceComponentV2();
void init();
void preload();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __INTELLIGENCE_COMP_V2_H__

View File

@@ -0,0 +1,55 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __LOGGING_COMP_H__
#define __LOGGING_COMP_H__
#include <memory>
#include "i_logging.h"
#include "i_messaging.h"
#include "singleton.h"
#include "i_mainloop.h"
#include "i_instance_awareness.h"
#include "i_socket_is.h"
#include "component.h"
#include "i_agent_details.h"
class LoggingComp
:
public Component,
Singleton::Provide<I_Logging>,
Singleton::Consume<I_Messaging>,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_InstanceAwareness>,
Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_Logging>,
Singleton::Consume<I_Socket>,
Singleton::Consume<I_AgentDetails>
{
public:
LoggingComp();
~LoggingComp();
void init();
void fini();
void preload();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __LOGGING_COMP_H__

View File

@@ -0,0 +1,54 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __MAINLOOP_H__
#define __MAINLOOP_H__
#include <memory>
#include "i_mainloop.h"
#include "i_environment.h"
#include "i_time_get.h"
#include "i_messaging.h"
#include "i_agent_details.h"
#include "i_signal_handler.h"
#include "singleton.h"
#include "component.h"
extern bool fini_signal_flag;
class MainloopComponent
:
public Component,
Singleton::Provide<I_MainLoop>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_Messaging>,
Singleton::Consume<I_AgentDetails>,
Singleton::Consume<I_SignalHandler>
{
public:
MainloopComponent();
~MainloopComponent();
void preload();
void init();
void fini();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __MAINLOOP_H__

View File

@@ -0,0 +1,467 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __MAYBE_RES_H__
#define __MAYBE_RES_H__
#include <string>
#include <ostream>
#include "common.h"
#include "debug.h"
#include "tostring.h"
template <typename Err>
class Error
{
template <typename T, typename TErr>
friend class Maybe;
public:
template<typename... Args>
Error(Args&&... args) : err(std::forward<Args>(args)...) {}
bool
operator==(const Error &other) const
{
return err == other.err;
}
template<class Archive>
void
serialize(Archive &ar, uint32_t)
{
ar(err);
}
static constexpr uint32_t getSerializationVersion() { return 0; }
private:
Err err;
};
template <>
class Error<void>
{
template <typename T, typename TErr>
friend class Maybe;
public:
template<typename... Args> Error(Args&&...) {}
bool operator==(const Error &) const { return true; }
template<class Archive> void serialize(Archive &ar, uint32_t) {}
};
// Wrapper templated functions, useful for creating Error class since the templating matching for them is better
template <typename Err, typename... Args>
Error<Err>
genError(Args&&... args)
{
return Error<Err>(std::forward<Args>(args)...);
}
template <typename Err>
Error<Err>
genError(Err err)
{
return Error<Err>(std::forward<Err>(err));
}
template <typename T, typename TErr = std::string>
class Maybe
{
public:
// Constructors from error or from value
Maybe(const Error<TErr> &_err) : set(false), err(_err) {}
Maybe(Error<TErr> &&_err) : set(false), err(std::move(_err)) {}
Maybe(const T &_val) : set(true), val(_val) {}
Maybe(T &&_val) : set(true), val(std::move(_val)) {}
// Constructors from another error class (which is convertible to TErr)
template<typename OTErr>
Maybe(const Error<OTErr> &_err) : set(false), err(_err.err) {}
template<typename OTErr>
Maybe(Error<OTErr> &&_err) : set(false), err(std::move(_err.err)) {}
// Constructors from another maybe class (if types are convertible)
template<typename OT, typename OTErr>
Maybe(const Maybe<OT, OTErr> &m) : set(m.ok())
{
if (set) {
new (&val) T(m.unpack());
} else {
new (&err) Error<TErr>(m.getErr());
}
}
template<typename OT, typename OTErr>
Maybe(Maybe<OT, OTErr> &&m) : set(m.ok())
{
if (set) {
new (&val) T(m.unpackMove());
} else {
new (&err) Error<TErr>(m.getErr());
}
}
Maybe(const Maybe &m);
Maybe(Maybe &&m);
~Maybe();
// Comparison operators
bool operator==(const Maybe &other) const;
bool operator!=(const Maybe &other) const { return !(*this==other); }
// Assignment - you can assing a new value, a new error, or a Maybe containing either
Maybe & operator=(const T &val);
Maybe & operator=(T &&val);
template<typename OTErr>
Maybe & operator=(const Error<OTErr> &err);
template<typename OTErr>
Maybe & operator=(Error<OTErr> &&err);
Maybe & operator=(const Maybe &other);
Maybe & operator=(Maybe &&other);
// Looking inside. Will assert if trying to get value/error when you have the other.
// ok - do we have a value (true) or error (false)?
// unpack/dereference - get the inner value.
// getErr - get the error.
// passErr - get the wrapper for the error, used for forwarding errors between different kinds of Maybes
// unpackMove - get an R-value reference to the inner value.
bool ok() const { return set; }
const T & unpack() const;
// LCOV_EXCL_START Reason: This function is tested in maybe_res_ut but marked as untested
const T & operator*() const { return unpack(); }
// LCOV_EXCL_STOP
const T * operator->() const { return &unpack(); }
T && unpackMove();
TErr getErr() const;
const Error<TErr> & passErr() const;
// Customized unpack & verify - throw the requested exception type on failure
template <class Exp, typename Aggregator = ToString, typename... Args>
void verify(Args... args) const;
template <class Exp, typename Aggregator = ToString, typename... Args>
const T & unpack(Args... args) const;
std::ostream & print(std::ostream &os) const;
template<class Archive>
void
save(Archive &ar, uint32_t) const
{
ar(set);
if (set) {
ar(val);
} else {
ar(err);
}
}
template<class Archive>
void
load(Archive &ar, uint32_t)
{
bool temp_set;
ar(temp_set);
if (temp_set) {
T temp_val;
ar(temp_val);
*this = temp_val;
} else {
Error<TErr> temp_err;
ar(temp_err);
*this = temp_err;
}
}
static constexpr uint32_t getSerializationVersion() { return 0; }
private:
bool set;
union {
T val;
Error<TErr> err;
};
};
template <typename TErr>
class Maybe<void, TErr>
{
class Nothing
{
};
public:
// Since void isn't a value that we can construct from, we use default constructor instead.
Maybe() : maybe(Nothing()) {}
// Constructors from error
Maybe(const Error<TErr> &_err) : maybe(_err) {}
Maybe(Error<TErr> &&_err) : maybe(std::move(_err)) {}
// Constructors from another error class (which is convertible to TErr)
template<typename OTErr>
Maybe(const Error<OTErr> &_err) : maybe(_err) {}
template<typename OTErr>
Maybe(Error<OTErr> &&_err) : maybe(std::move(_err)) {}
Maybe(const Maybe &) = default;
Maybe(Maybe &&) = default;
~Maybe() {}
// Comparison operators
bool operator==(const Maybe &other) const { return maybe == other.maybe; }
bool operator!=(const Maybe &other) const { return !(*this==other); }
// Assignment - you can assing a new error, or a Maybe containing either error or `void`
template<typename OTErr>
Maybe & operator=(const Error<OTErr> &err) { maybe = err; return *this; }
// LCOV_EXCL_START Reason: coverage upgrade
template<typename OTErr>
Maybe & operator=(Error<OTErr> &&err) { maybe = std::move(err); return *this; }
// LCOV_EXCL_STOP
Maybe & operator=(const Maybe &other) { maybe = other.maybe; return *this; }
Maybe & operator=(Maybe &&other) { maybe = std::move(other.maybe); return *this; }
// Looking inside. Will assert if trying to get error when you have a `void`.
// ok - do we have a `void` (true) or error (false)?
// getErr - get the error.
// passErr - get the wrapper for the error, used for forwarding errors between different kinds of Maybes
bool ok() const { return maybe.ok(); }
TErr getErr() const { return maybe.getErr(); }
const Error<TErr> & passErr() const { return maybe.passErr(); }
// Customized verify - throw the requested exception type on failure
template <typename... Args>
void verify(Args... args) const { maybe.verify(std::forward(args)...); }
std::ostream &
print(std::ostream &os) const
{
if (ok()) return os << "Value()";
return os << "Error(" << getErr() << ")";
}
template<class Archive>
void
serialize(Archive &ar)
{
ar(maybe);
}
private:
Maybe<Nothing, TErr> maybe;
};
//
// Method Implementations
//
template <typename T, typename TErr>
Maybe<T, TErr>::Maybe(const Maybe<T, TErr> &m)
:
set(m.set)
{
if (set) {
new (&val) T(m.val);
} else {
new (&err) Error<TErr>(m.err);
}
}
template <typename T, typename TErr>
Maybe<T, TErr>::Maybe(Maybe<T, TErr> &&m)
:
set(m.set)
{
if (set) {
new (&val) T(std::move(m.val));
} else {
new (&err) Error<TErr>(std::move(m.err));
}
}
template <typename T, typename TErr>
Maybe<T, TErr>::~Maybe()
{
if (set) {
val.~T();
} else {
err.~Error<TErr>();
}
}
template <typename T, typename TErr>
bool
Maybe<T, TErr>::operator==(const Maybe<T, TErr> &other) const
{
if (set != other.set) return false;
if (set) {
return val == other.val;
} else {
return err == other.err;
}
}
template <typename T, typename TErr>
const T &
Maybe<T, TErr>::unpack() const
{
dbgAssert(set) << "Maybe value is not set";
return val;
}
template <typename T, typename TErr>
T &&
Maybe<T, TErr>::unpackMove()
{
dbgAssert(set) << "No value to be moved";
return std::move(val);
}
template <typename T, typename TErr>
TErr
Maybe<T, TErr>::getErr() const
{
dbgAssert(!set) << "Maybe value is set";
return err.err;
}
template <typename T, typename TErr>
const Error<TErr> &
Maybe<T, TErr>::passErr() const
{
dbgAssert(!set) << "Maybe value is set";
return err;
}
template <typename T, typename TErr>
template <class Exp, typename Aggregator, typename... Args>
void
Maybe<T, TErr>::verify(Args... args) const
{
if (!set) throw Exp(Aggregator(std::forward<Args>(args)..., err.err));
}
template <typename T, typename TErr>
template <class Exp, typename Aggregator, typename... Args>
const T &
Maybe<T, TErr>::unpack(Args... args) const
{
if (!set) throw Exp(Aggregator(std::forward<Args>(args)..., err.err));
return val;
}
template <typename T, typename TErr>
Maybe<T, TErr> &
Maybe<T, TErr>::operator=(const T &_val)
{
if (set) {
val = _val;
} else {
err.~Error<TErr>();
set = true;
new (&val) T(_val);
}
return *this;
}
template <typename T, typename TErr>
Maybe<T, TErr> &
Maybe<T, TErr>::operator=(T &&_val)
{
if (set) {
val = std::move(_val);
} else {
err.~Error<TErr>();
set = true;
new (&val) T(std::move(_val));
}
return *this;
}
template <typename T, typename TErr>
template<typename OTErr>
Maybe<T, TErr> &
Maybe<T, TErr>::operator=(const Error<OTErr> &_err)
{
if (!set) {
err = _err.err;
} else {
val.~T();
set = false;
new (&err) Error<TErr>(_err.err);
}
return *this;
}
template <typename T, typename TErr>
template<typename OTErr>
Maybe<T, TErr> &
Maybe<T, TErr>::operator=(Error<OTErr> &&_err)
{
if (!set) {
err = std::move(_err.err);
} else {
val.~T();
set = false;
new (&err) Error<TErr>(std::move(_err.err));
}
return *this;
}
template <typename T, typename TErr>
Maybe<T, TErr> &
Maybe<T, TErr>::operator=(const Maybe<T, TErr> &other)
{
if (other.set) {
*this = other.val;
} else {
*this = other.err;
}
return *this;
}
template <typename T, typename TErr>
Maybe<T, TErr> &
Maybe<T, TErr>::operator=(Maybe<T, TErr> &&other)
{
if (other.set) {
*this = std::move(other.val);
} else {
*this = std::move(other.err);
}
return *this;
}
template <typename T, typename TErr>
std::ostream &
Maybe<T, TErr>::print(std::ostream &os) const
{
if (ok()) return os << "Value(" << unpack() << ")";
return os << "Error(" << getErr() << ")";
}
// Formatting operator. Prints either the value or the error.
template <typename T, typename TErr>
std::ostream &
operator<<(std::ostream &os, const Maybe<T, TErr> &maybe)
{
return maybe.print(os);
}
#endif // __MAYBE_RES_H__

View File

@@ -0,0 +1,46 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __REST_SERVER__
#define __REST_SERVER__
#include <memory>
#include "i_rest_api.h"
#include "i_mainloop.h"
#include "singleton.h"
#include "i_environment.h"
#include "component.h"
class RestServer
:
public Component,
Singleton::Provide<I_RestApi>,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_Environment>
{
public:
RestServer();
~RestServer();
void preload();
void init();
void fini();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __REST_SERVER__

View File

@@ -0,0 +1,91 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __SCOPE_EXIT_H__
#define __SCOPE_EXIT_H__
// Scope Exit - executes some code when an instance of this class falls off scope.
// This is very useful when a clean-up operation is needed due to pre-mature / exception.
// Example usage:
//
// work_t work;
// auto guard = scope_guard([&]{ work.rollback(); }); // access to local/class vars allowed in code
// work.do_work(); // may throw
// if (!work.success()) return false; // premature exit
// guard.release();
// return true;
//
//
// Code taken from N4189 pending standard - www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189.pdf
// (with some minor adaptations for C++11)
#include <type_traits> // For ::std::remove_reference
namespace std
{
template <typename EF>
class scope_exit
{
// private must come first due to use of noexcept in dtor
private:
EF exit_function;
bool execute_on_destruction;
public:
// ctor
explicit scope_exit(EF &&f) noexcept
:
exit_function(::std::move(f)),
execute_on_destruction{true}
{}
// dtor
~scope_exit()
{
if (execute_on_destruction) this->exit_function();
}
// LCOV_EXCL_START Reason: coverage upgrade
// move
scope_exit(scope_exit &&rhs) noexcept
:
exit_function(::std::move(rhs.exit_function)),
execute_on_destruction{rhs.execute_on_destruction}
{
rhs.release();
}
// LCOV_EXCL_STOP
void
release() noexcept
{
this->execute_on_destruction = false;
}
private:
scope_exit(const scope_exit &) = delete;
void operator=(const scope_exit &) = delete;
scope_exit & operator=(scope_exit &&) = delete;
};
template <typename EF>
scope_exit<typename ::std::remove_reference<EF>::type>
make_scope_exit(EF &&exit_function) noexcept
{
return scope_exit<typename ::std::remove_reference<EF>::type>(::std::forward<EF>(exit_function));
}
} // namespace std
#endif // __SCOPE_EXIT_H__

View File

@@ -0,0 +1,71 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __SHMPKTQUEUE_H__
#define __SHMPKTQUEUE_H__
#include <net/ethernet.h>
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct shm_pkt_queue_stub shm_pkt_queue_stub;
typedef enum {
shmq_msg_mode_l2 = 0x01, // Layer 2 packet
shmq_msg_mode_l3 = 0x02, // Layer 3 packet
shmq_msg_mode_bb = 0x04, // Packet need to be bounced back to incoming interface
} shmq_msg_mode;
typedef enum {
shmq_msg_no_proto = 0,
shmq_msg_proto_ipv4 = ETHERTYPE_IP, // Internet Protocol version 4
shmq_msg_proto_ipv6 = ETHERTYPE_IPV6, // Internet Protocol version 6
} shm_pkt_msg_proto;
typedef struct {
uint16_t mode; // Of type: shmq_msg_mode. Message mode flags.
uint16_t l3_proto; // Of type: shm_pkt_msg_proto. Message protocol: IPv4/IPv6, etc.
uint16_t len; // Data length
uint16_t maclen; // MAC header length. TODO: Remove it. Data content should be is enough
uint16_t if_index; // VPP Interface index
unsigned char data[0];
} shm_pkt_queue_msg_hdr;
shm_pkt_queue_stub *get_shm_pkt_queue_id();
int init_shm_pkt_queue(shm_pkt_queue_stub *id, const char *shm_name, const char *queue_name);
int push_to_shm_pkt_queue(
shm_pkt_queue_stub *id,
const unsigned char *msg,
uint16_t length,
shmq_msg_mode mode,
shm_pkt_msg_proto l3_proto,
uint16_t l2_length,
uint16_t if_index
);
unsigned char *pop_from_shm_pkt_queue(shm_pkt_queue_stub *id);
int is_shm_pkt_queue_empty(shm_pkt_queue_stub *id);
void delete_shm_pkt_queue(shm_pkt_queue_stub *id);
#ifdef __cplusplus
}
#endif
#endif // __SHMPKTQUEUE_H__

View File

@@ -0,0 +1,75 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __SINGLETON_H__
#define __SINGLETON_H__
#include <typeinfo>
#include <typeindex>
#include <map>
#include <set>
#include <memory>
#include "common.h"
class Singleton
{
public:
template <class I_Face>
class Provide;
template <class I_Face>
class Consume;
template <typename T>
static bool exists();
// Dealing with owned singletons - see advanced topics.
class OwnedSingleton;
template <typename DerivedFromOwnedSingleton>
static DerivedFromOwnedSingleton * getOwned();
template <typename DerivedFromOwnedSingleton>
static bool existsOwned();
template <typename DerivedFromOwnedSingleton, typename ... BuildArgs>
static void newOwned(BuildArgs ... args);
template <typename DerivedFromOwnedSingleton>
static void deleteOwned();
template <typename DerivedFromOwnedSingleton>
static void setOwned(std::unique_ptr<DerivedFromOwnedSingleton> &&ptr);
private:
Singleton() {}
template <typename I_Face>
static I_Face * get();
static void registerSingleton(std::type_index type, void *ptr);
static void unregisterSingleton(std::type_index type, void *ptr);
static void * get(const std::type_index &index);
static bool exists(const std::type_index &index);
static std::map<std::type_index, std::set<void *>> singles;
static std::map<std::type_index, std::unique_ptr<OwnedSingleton>> owned_singles;
};
template <typename Component, typename Interface>
Interface * getInterface();
#include "impl/singleton.h"
#endif // __SINGLETON_H__

View File

@@ -0,0 +1,51 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __TABLE_H__
#define __TABLE_H__
#include <memory>
#include "i_table.h"
#include "i_environment.h"
#include "i_mainloop.h"
#include "i_time_get.h"
#include "singleton.h"
#include "component.h"
template <typename Key>
class Table
:
public Component,
Singleton::Provide<I_Table>,
Singleton::Provide<I_TableSpecific<Key>>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_MainLoop>
{
public:
Table();
~Table();
void init();
void fini();
void preload();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#include "table/table_impl.h"
#endif // __TABLE_H__

View File

@@ -0,0 +1,220 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ENTRY_IMPL_H__
#define __ENTRY_IMPL_H__
#ifndef __TABLE_IMPL_H__
#error "entry_impl.h should not be included directly"
#endif // __TABLE_IMPL_H__
USE_DEBUG_FLAG(D_TABLE);
template <typename Key>
class Table<Key>::Impl::Entry
{
using KeyNodePtr = TableHelper::KeyNodePtr<Key>;
using ListInterface = TableHelper::I_InternalTableList<KeyNodePtr> *;
using ExpirationInterface = TableHelper::I_InternalTableExpiration<Key, ExpIter> *;
using ms = std::chrono::microseconds;
public:
Entry(ListInterface _table, ExpirationInterface _expiration, const Key &key, const KeyNodePtr &ptr, ms expire);
bool hasState(std::type_index index) const;
bool createState(const std::type_index &index, std::unique_ptr<TableOpaqueBase> &&ptr);
bool delState(const std::type_index &index);
TableOpaqueBase * getState(const std::type_index &index);
void addKey(const Key &key, const KeyNodePtr &ptr);
void removeSelf();
void setExpiration(ms expire);
std::chrono::microseconds getExpiration();
std::vector<Key> getKeys();
void uponEnteringContext();
void uponLeavingContext();
template <class Archive>
void save(Archive &ar) const;
template <class Archive>
void load(Archive &ar);
private:
ListInterface table;
ExpirationInterface expiration;
std::unordered_map<Key, KeyNodePtr> keys;
std::unordered_map<std::type_index, std::unique_ptr<TableOpaqueBase>> opaques;
ExpIter expr_iter;
};
template <typename Key>
Table<Key>::Impl::Entry::Entry(
ListInterface _table,
ExpirationInterface _expiration,
const Key &key,
const KeyNodePtr &ptr,
ms expire)
:
table(_table),
expiration(_expiration)
{
addKey(key, ptr);
expr_iter = expiration->addExpiration(expire, key);
}
template <typename Key>
bool
Table<Key>::Impl::Entry::hasState(std::type_index index) const
{
return opaques.count(index) != 0;
}
template <typename Key>
bool
Table<Key>::Impl::Entry::createState(const std::type_index &index, std::unique_ptr<TableOpaqueBase> &&ptr)
{
if (hasState(index)) {
dbgError(D_TABLE) << "Failed to recreate a state of type " << index.name();
return false;
}
dbgTrace(D_TABLE) << "Creating a state of type " << index.name();
return opaques.emplace(index, std::move(ptr)).second;
}
template <typename Key>
bool
Table<Key>::Impl::Entry::delState(const std::type_index &index)
{
dbgTrace(D_TABLE) << "Deleting state of type " << index.name();
auto iter = opaques.find(index);
if (iter == opaques.end()) return false;
opaques.erase(iter);
return true;
}
template <typename Key>
TableOpaqueBase *
Table<Key>::Impl::Entry::getState(const std::type_index &index)
{
auto iter = opaques.find(index);
if (iter == opaques.end()) return nullptr;
return iter->second.get();
}
template <typename Key>
void
Table<Key>::Impl::Entry::addKey(const Key &key, const KeyNodePtr &ptr)
{
keys[key] = ptr;
}
template <typename Key>
void
Table<Key>::Impl::Entry::removeSelf()
{
expiration->removeExpiration(expr_iter);
for (auto &iter : keys) {
table->removeKey(iter.second);
}
keys.clear();
opaques.clear();
}
template <typename Key>
void
Table<Key>::Impl::Entry::setExpiration(ms expire)
{
expiration->removeExpiration(expr_iter);
expr_iter = expiration->addExpiration(expire, keys.begin()->first);
}
template <typename Key>
std::chrono::microseconds
Table<Key>::Impl::Entry::getExpiration()
{
return expr_iter->getExpiration();
}
template <typename Key>
std::vector<Key>
Table<Key>::Impl::Entry::getKeys()
{
std::vector<Key> keys_vec;
keys_vec.reserve(keys.size());
for (auto &iter : keys) {
keys_vec.emplace_back(iter.first);
}
return keys_vec;
}
template <typename Key>
void
Table<Key>::Impl::Entry::uponEnteringContext()
{
for (auto &opauqe : opaques) {
opauqe.second->uponEnteringContext();
}
}
template <typename Key>
void
Table<Key>::Impl::Entry::uponLeavingContext()
{
for (auto &opauqe : opaques) {
opauqe.second->uponLeavingContext();
}
}
template <typename Key>
template <class Archive>
void
Table<Key>::Impl::Entry::save(Archive &ar) const
{
std::vector<std::string> opaque_names;
opaque_names.reserve(opaques.size());
for (auto &iter : opaques) {
opaque_names.emplace_back(iter.second->nameOpaque());
}
ar(cereal::make_nvp("opaque_names", opaque_names));
for (auto &iter : opaques) {
// 0 is used currently until supporting versions
iter.second->saveOpaque(ar, 0);
}
}
template <typename Key>
template <class Archive>
void
Table<Key>::Impl::Entry::load(Archive &ar)
{
std::vector<std::string> opaque_names;
ar(cereal::make_nvp("opaque_names", opaque_names));
auto &rep = ::cereal::detail::StaticObject<TableOpaqueRep>::getInstance();
for (auto &iter : opaque_names) {
auto opaque = rep.getOpaqueByName(iter);
if (!opaque) {
dbgTrace(D_TABLE) << "Failed to load synced opaque " << iter;
return;
}
// 0 is used currently until supporting versions
opaque->loadOpaque(ar, 0);
if (!createState(typeid(*opaque), move(opaque))) {
dbgError(D_TABLE) << "Failed to create the state for opaque " << iter;
}
}
}
#endif // __ENTRY_IMPL_H__

View File

@@ -0,0 +1,117 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __EXPIRATION_IMPL_H__
#define __EXPIRATION_IMPL_H__
#ifndef __TABLE_IMPL_H__
#error "expiration_impl.h should not be included directly"
#endif // __TABLE_IMPL_H__
template <typename Key>
class Table<Key>::Impl::ExpirationEntry
{
public:
ExpirationEntry(std::chrono::microseconds _expire, const Key &_key);
bool isBeforeTime(std::chrono::microseconds other_expire) const;
const Key & getKey() const;
std::chrono::microseconds getExpiration() const;
private:
std::chrono::microseconds expire;
Key key;
};
template <typename Key>
Table<Key>::Impl::ExpirationEntry::ExpirationEntry(std::chrono::microseconds _expire, const Key &_key)
:
expire(_expire),
key(_key)
{
}
template <typename Key>
bool
Table<Key>::Impl::ExpirationEntry::isBeforeTime(std::chrono::microseconds other_expire) const
{
return expire <= other_expire;
}
template <typename Key>
const Key &
Table<Key>::Impl::ExpirationEntry::getKey() const
{
return key;
}
template <typename Key>
std::chrono::microseconds
Table<Key>::Impl::ExpirationEntry::getExpiration() const
{
return expire;
}
template <typename Key>
class Table<Key>::Impl::ExpList
:
public TableHelper::I_InternalTableExpiration<Key, ExpIter>
{
public:
ExpIter addExpiration(std::chrono::microseconds expire, const Key &key) override;
void removeExpiration(const ExpIter &iter) override;
bool shouldExpire(std::chrono::microseconds expire) const;
const Key & getEarliest() const;
private:
std::list<ExpirationEntry> list;
};
template <typename Key>
typename Table<Key>::Impl::ExpIter
Table<Key>::Impl::ExpList::addExpiration(std::chrono::microseconds expire, const Key &key)
{
// The list is ordered from the highest value (in the far future) to the lowest (in the near future).
// So we scan the list to enter before the first vlaue that is smaller than us (typically, the first one).
for (auto iter = list.begin(); iter != list.end(); iter++) {
if (iter->isBeforeTime(expire)) {
return list.emplace(iter, expire, key);
}
}
// There was no value that is closer to the current time, so it should be placed in at the end of the list.
return list.emplace(list.end(), expire, key);
}
template <typename Key>
void
Table<Key>::Impl::ExpList::removeExpiration(const ExpIter &iter)
{
list.erase(iter);
}
template <typename Key>
bool
Table<Key>::Impl::ExpList::shouldExpire(std::chrono::microseconds expire) const
{
if (list.empty()) return false;
return list.back().isBeforeTime(expire);
}
template <typename Key>
const Key &
Table<Key>::Impl::ExpList::getEarliest() const
{
dbgAssert(!list.empty()) << "Cannot access the earliest member of an empty list";
return list.back().getKey();
}
#endif // __EXPIRATION_IMPL_H__

View File

@@ -0,0 +1,55 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __TABLE_HELPERS_H__
#define __TABLE_HELPERS_H__
#ifndef __TABLE_IMPL_H__
#error "table_helpers.h should not be included directly"
#endif // __TABLE_IMPL_H__
#include "context.h"
namespace TableHelper
{
class Constant
{
protected:
static const std::string primary_key;
};
template <typename KeyPtr>
class I_InternalTableList
{
public:
virtual void removeKey(const KeyPtr &key) = 0;
protected:
~I_InternalTableList() {}
};
template <typename Key, typename ExpIter>
class I_InternalTableExpiration
{
public:
virtual ExpIter addExpiration(std::chrono::microseconds expire, const Key &key) = 0;
virtual void removeExpiration(const ExpIter &iter) = 0;
protected:
~I_InternalTableExpiration() {}
};
} // TableHelper
#endif // __TABLE_HELPERS_H__

View File

@@ -0,0 +1,442 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __TABLE_IMPL_H__
#define __TABLE_IMPL_H__
#ifndef __TABLE_H__
#error "table_impl.h should not be included directly"
#endif // __TABLE_H__
#include <sstream>
#include <memory>
#include <iostream>
#include "debug.h"
#include "time_print.h"
#include "singleton.h"
#include "context.h"
#include "table/table_helpers.h"
#include "table/table_list.h"
#include "table/opaque_repo.h"
#include "config.h"
USE_DEBUG_FLAG(D_TABLE);
template <typename Key>
class Table<Key>::Impl
:
public TableHelper::Constant,
public TableHelper::I_InternalTableList<TableHelper::KeyNodePtr<Key>>,
public Singleton::Provide<I_Table>::From<Table<Key>>,
public Singleton::Provide<I_TableSpecific<Key>>::template From<Table<Key>>
{
class ExpirationEntry;
using ExpIter = typename std::list<ExpirationEntry>::iterator;
class ExpList;
class Entry;
using EntryRef = std::shared_ptr<Entry>;
using EntryMap = std::unordered_map<Key, EntryRef>;
public:
void init();
void fini();
// I_InternalTableControl methods
void removeKey(const TableHelper::KeyNodePtr<Key> &key) override;
// I_Table protected methods
bool hasState (const std::type_index &index) const override;
bool createState(const std::type_index &index, std::unique_ptr<TableOpaqueBase> &&ptr) override;
bool deleteState(const std::type_index &index) override;
TableOpaqueBase * getState (const std::type_index &index) override;
// I_Table public methods
void setExpiration(std::chrono::milliseconds expire) override;
bool doesKeyExists() const override;
std::string keyToString () const override;
TableIter begin () const override;
TableIter end () const override;
// I_TableSpecific methods
bool hasEntry (const Key &key) override;
bool createEntry (const Key &key, std::chrono::microseconds expire) override;
bool deleteEntry (const Key &key) override;
bool addLinkToEntry(const Key &key, const Key &link) override;
uint count () override;
void expireEntries () override;
bool setActiveKey (const Key &key) override;
void unsetActiveKey() override;
Maybe<Key, void> getCurrentKey () const override;
void saveEntry (TableIter iter, SyncMode mode, cereal::BinaryOutputArchive &ar) const override;
void loadEntry (cereal::BinaryInputArchive &ar) override;
private:
EntryRef getCurrEntry() const;
// Members
EntryMap entries;
ExpList expiration;
TableHelper::KeyList<Key> list;
Context ctx;
// Interfaces
I_TimeGet *timer = nullptr;
I_Environment *env = nullptr;
};
#include "table/entry_impl.h"
#include "table/expiration_impl.h"
template <typename Key>
void
Table<Key>::Impl::init()
{
env = Singleton::Consume<I_Environment>::by<Table<Key>>();
timer = Singleton::Consume<I_TimeGet>::by<Table<Key>>();
auto mainloop = Singleton::Consume<I_MainLoop>::by<Table<Key>>();
mainloop->addRecurringRoutine(
I_MainLoop::RoutineType::Timer,
std::chrono::milliseconds(100),
[&] () { expireEntries(); },
"Delete expired table entries"
);
}
template <typename Key>
void
Table<Key>::Impl::fini()
{
while (count() > 0) {
deleteEntry(expiration.getEarliest());
}
env = nullptr;
timer = nullptr;
}
template <typename Key>
void
Table<Key>::Impl::removeKey(const TableHelper::KeyNodePtr<Key> &key)
{
if (!key) {
dbgError(D_TABLE) << "Function called without a key";
return;
}
auto iter = entries.find(key->getKey());
if (iter == entries.end()) {
dbgError(D_TABLE) << "Trying to remove a non-existing key " << key;
return;
}
dbgTrace(D_TABLE) << "Removing the key " << key;
entries.erase(iter);
list.removeKey(key);
}
template <typename Key>
bool
Table<Key>::Impl::hasState(const std::type_index &index) const
{
dbgTrace(D_TABLE) << "Checking if there is a state of type " << index.name();
auto entry = getCurrEntry();
if (!entry) return false;
return entry->hasState(index);
}
template <typename Key>
bool
Table<Key>::Impl::createState(const std::type_index &index, std::unique_ptr<TableOpaqueBase> &&ptr)
{
auto ent = getCurrEntry();
if (ent == nullptr) {
dbgError(D_TABLE) << "Trying to create a state without an entry";
return false;
}
return ent->createState(index, std::move(ptr));
}
template <typename Key>
bool
Table<Key>::Impl::deleteState(const std::type_index &index)
{
auto ent = getCurrEntry();
if (ent) return ent->delState(index);
return false;
}
template <typename Key>
TableOpaqueBase *
Table<Key>::Impl::getState(const std::type_index &index)
{
auto ent = getCurrEntry();
dbgTrace(D_TABLE) << "Getting a state of type " << index.name();
if (!ent) return nullptr;
return ent->getState(index);
}
template <typename Key>
void
Table<Key>::Impl::setExpiration(std::chrono::milliseconds expire)
{
auto ent = getCurrEntry();
if (!ent) return;
auto curr_time = timer->getMonotonicTime();
ent->setExpiration(curr_time + expire);
}
template <typename Key>
bool
Table<Key>::Impl::doesKeyExists() const
{
auto key = env->get<Key>(primary_key);
if (!key.ok()) return false;
return entries.find(key.unpack()) != entries.end();
}
template <typename Key>
std::string
Table<Key>::Impl::keyToString() const
{
auto key = env->get<Key>(primary_key);
if (!key.ok()) return "";
std::ostringstream os;
os << key.unpack();
return os.str();
}
template <typename Key>
TableIter
Table<Key>::Impl::begin() const
{
return TableIter(list.begin());
}
template <typename Key>
TableIter
Table<Key>::Impl::end() const
{
return TableIter(list.end());
}
template <typename Key>
bool
Table<Key>::Impl::hasEntry(const Key &key)
{
return entries.find(key) != entries.end();
}
template <typename Key>
bool
Table<Key>::Impl::createEntry(const Key &key, std::chrono::microseconds expire)
{
if (entries.find(key) != entries.end()) {
dbgWarning(D_TABLE) << "Trying to recreate an entry with the key " << key;
return false;
}
auto curr_time = timer->getMonotonicTime();
auto expire_time = curr_time + expire;
dbgTrace(D_TABLE) << "Creating an entry with the key " << key << " for " << expire;
entries.emplace(key, std::make_shared<Entry>(this, &expiration, key, list.addKey(key), expire_time));
return true;
}
template <typename Key>
bool
Table<Key>::Impl::deleteEntry(const Key &key)
{
auto iter = entries.find(key);
if (iter == entries.end()) {
dbgWarning(D_TABLE) << "Trying to delete a non-existing entry of the key " << key;
return false;
}
auto ent = iter->second; // Important, since we don't want the entry to disappear before we leave the function.
dbgTrace(D_TABLE) << "Deleting an entry of the key " << key;
ent->removeSelf();
return true;
}
template <typename Key>
bool
Table<Key>::Impl::addLinkToEntry(const Key &key, const Key &link)
{
auto iter = entries.find(key);
if (iter == entries.end()) {
dbgWarning(D_TABLE) << "No entry, to which to add a key";
return false;
}
bool success = entries.emplace(link, iter->second).second;
if (!success) {
dbgWarning(D_TABLE) << "Attempting to re-enter a key " <<link;
return false;
}
dbgTrace(D_TABLE) << "Linking the key " << link << " with the key " << key;
iter->second->addKey(link, list.addKey(link));
return true;
}
template <typename Key>
uint
Table<Key>::Impl::count()
{
return entries.size();
}
template <typename Key>
void
Table<Key>::Impl::expireEntries()
{
auto curr_time = timer->getMonotonicTime();
while (expiration.shouldExpire(curr_time)) {
auto key = expiration.getEarliest();
ScopedContext ctx;
ctx.registerValue(primary_key, key);
deleteEntry(key);
}
}
template <typename Key>
bool
Table<Key>::Impl::setActiveKey(const Key &key)
{
auto entry = entries.find(key);
if (entry == entries.end()) return false;
ctx.registerValue(primary_key, key);
ctx.activate();
entry->second->uponEnteringContext();
return true;
}
template <typename Key>
void
Table<Key>::Impl::unsetActiveKey()
{
auto entry = getCurrEntry();
if (entry == nullptr) {
dbgError(D_TABLE) << "Unsetting the active key when there is no active entry";
return;
}
entry->uponLeavingContext();
ctx.deactivate();
}
template <typename Key>
Maybe<Key, void>
Table<Key>::Impl::getCurrentKey() const
{
return env->get<Key>(primary_key);
}
template <typename Key>
typename Table<Key>::Impl::EntryRef
Table<Key>::Impl::getCurrEntry() const
{
auto key = env->get<Key>(primary_key);
if (!key.ok()) {
dbgTrace(D_TABLE) << "Key was not found";
return nullptr;
}
auto iter = entries.find(key.unpack());
if (iter == entries.end()) {
dbgTrace(D_TABLE) << "No entry matches the key " << key.unpack();
return nullptr;
}
return iter->second;
}
template <typename Key>
void
Table<Key>::Impl::saveEntry(TableIter iter, SyncMode mode, cereal::BinaryOutputArchive &ar) const
{
iter.setEntry();
auto ent = getCurrEntry();
ar(
cereal::make_nvp("keys_vec", ent->getKeys()),
cereal::make_nvp("expire", ent->getExpiration())
);
ent->save(ar);
if (mode == SyncMode::TRANSFER_ENTRY) {
std::string key = keyToString();
ent->removeSelf();
dbgTrace(D_TABLE) << "Key '" << key <<"' was removed";
}
iter.unsetEntry();
}
template <typename Key>
void
Table<Key>::Impl::loadEntry(cereal::BinaryInputArchive &ar)
{
std::vector<Key> keys_vec;
std::chrono::microseconds expire;
ar(
cereal::make_nvp("keys_vec", keys_vec),
cereal::make_nvp("expire", expire)
);
if (keys_vec.size() == 0) {
dbgError(D_TABLE) << "No Keys to load";
return;
}
if (!createEntry(keys_vec[0], expire)) {
dbgError(D_TABLE) << "Cannot create a new entry";
return;
}
for (decltype(keys_vec.size()) index=1; index<keys_vec.size(); index++) {
if (!addLinkToEntry(keys_vec[0], keys_vec[index])) {
dbgError(D_TABLE) << "Cannot add link to an entry";
return;
}
}
auto entry_iter = entries.find(keys_vec[0]);
if (entry_iter == entries.end()) return;
auto ent = entry_iter->second;
ent->load(ar);
}
template <typename Key>
Table<Key>::Table() : Component("Table"), pimpl(std::make_unique<Table::Impl>())
{
}
template <typename Key>
Table<Key>::~Table()
{
}
template <typename Key>
void
Table<Key>::init()
{
pimpl->init();
}
template <typename Key>
void
Table<Key>::fini()
{
pimpl->fini();
}
template <typename Key>
void
Table<Key>::preload()
{
}
#endif // __TABLE_IMPL_H__

View File

@@ -0,0 +1,96 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __TABLE_LIST_H__
#define __TABLE_LIST_H__
#ifndef __TABLE_IMPL_H__
#error "table_list.h should not be included directly"
#endif // __TABLE_IMPL_H__
#include "table/table_list_node.h"
#include "table/table_list_iter.h"
#include "debug.h"
USE_DEBUG_FLAG(D_TABLE);
namespace TableHelper
{
template <typename Key>
class KeyList
{
public:
KeyNodePtr<Key> addKey(const Key &key);
void removeKey(const KeyNodePtr<Key> &val);
std::shared_ptr<I_TableIter> begin() const;
std::shared_ptr<I_TableIter> end() const;
private:
KeyNodePtr<Key> first;
KeyNodePtr<Key> last;
};
template <typename Key>
KeyNodePtr<Key>
KeyList<Key>::addKey(const Key &key)
{
KeyNodePtr<Key> new_entry = std::make_shared<KeyNode<Key>>(key);
if (!first) {
first = new_entry;
} else {
last->setNext(new_entry);
}
last = new_entry;
return new_entry;
};
template <typename Key>
void
KeyList<Key>::removeKey(const KeyNodePtr<Key> &val)
{
val->deactivate();
if (val == first) {
first = first->getNext();
if (last == val) last = first; // `val` was the only member of the list
return;
}
for (auto iter = first; iter != last; iter = iter->getNext()) {
if (iter->getNext() == val) {
if (iter->getNext() == last) last = iter;
iter->setNext(iter->getNext()->getNext());
return;
}
}
dbgError(D_TABLE) << "Iterator was not found in the table key list";
}
template <typename Key>
std::shared_ptr<I_TableIter>
KeyList<Key>::begin() const
{
return std::make_shared<KeyNodeIter<Key>>(first);
}
template <typename Key>
std::shared_ptr<I_TableIter>
KeyList<Key>::end() const
{
return std::make_shared<KeyNodeIter<Key>>(nullptr);
}
} // TableHelper
#endif // __TABLE_LIST_H__

View File

@@ -0,0 +1,98 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __TABLE_LIST_ITER_H__
#define __TABLE_LIST_ITER_H__
#ifndef __TABLE_IMPL_H__
#error "table_list_iter.h should not be included directly"
#endif // __TABLE_IMPL_H__
#include "context.h"
namespace TableHelper
{
template <typename Key>
class KeyNodeIter : public I_TableIter, public Constant
{
public:
KeyNodeIter(const KeyNodePtr<Key> &iter);
void operator++() override;
void operator++(int) override;
void setEntry() override;
void unsetEntry() override;
void * getUniqueId() const override;
private:
void moveNext();
KeyNodePtr<Key> curr;
Context ctx;
};
template <typename Key>
KeyNodeIter<Key>::KeyNodeIter(const KeyNodePtr<Key> &iter) : curr(iter)
{
}
template <typename Key>
void
KeyNodeIter<Key>::operator++()
{
moveNext();
}
template <typename Key>
void
KeyNodeIter<Key>::operator++(int)
{
moveNext();
}
template <typename Key>
void
KeyNodeIter<Key>::setEntry()
{
if (!curr || !curr->isActive()) return;
ctx.registerValue(primary_key, curr->getKey());
ctx.activate();
}
template <typename Key>
void
KeyNodeIter<Key>::unsetEntry()
{
ctx.deactivate();
}
template <typename Key>
void *
KeyNodeIter<Key>::getUniqueId() const
{
return curr.get();
}
template <typename Key>
void
KeyNodeIter<Key>::moveNext()
{
while (curr != nullptr) {
curr = curr->getNext();
if (curr != nullptr && curr->isActive()) return;
}
}
} // TableHelper
#endif // __TABLE_LIST_ITER_H__

View File

@@ -0,0 +1,87 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __TABLE_LIST_NODE_H__
#define __TABLE_LIST_NODE_H__
#ifndef __TABLE_IMPL_H__
#error "table_list_node.h should not be included directly"
#endif // __TABLE_IMPL_H__
namespace TableHelper
{
template <typename Key>
class KeyNode
{
public:
KeyNode(const Key &_key);
void setNext(const std::shared_ptr<KeyNode> &_next);
const Key & getKey() const;
const std::shared_ptr<KeyNode> & getNext() const;
bool isActive() const;
void deactivate();
private:
Key key;
std::shared_ptr<KeyNode> next;
bool is_active = true;
};
template <typename Key>
KeyNode<Key>::KeyNode(const Key &_key)
:
key(_key)
{
}
template <typename Key>
void
KeyNode<Key>::setNext(const std::shared_ptr<KeyNode> &_next)
{
next = _next;
}
template <typename Key>
const Key &
KeyNode<Key>::getKey() const
{
return key;
}
template <typename Key>
const std::shared_ptr<KeyNode<Key>> &
KeyNode<Key>::getNext() const
{
return next;
}
template <typename Key>
bool
KeyNode<Key>::isActive() const
{
return is_active;
}
template <typename Key>
void
KeyNode<Key>::deactivate()
{
is_active = false;
}
template <typename Key> using KeyNodePtr = std::shared_ptr<KeyNode<Key>>;
} // TableHelper
#endif // __TABLE_LIST_NODE_H__

View File

@@ -0,0 +1,52 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __TENANT_MANAGER_H__
#define __TENANT_MANAGER_H__
#include "i_tenant_manager.h"
#include "i_messaging.h"
#include "i_rest_api.h"
#include "i_mainloop.h"
#include "i_time_get.h"
#include "i_instance_awareness.h"
#include "component.h"
enum class TenantManagerType { CLIENT, SERVER };
class TenantManager
:
public Component,
Singleton::Provide<I_TenantManager>,
Singleton::Consume<I_InstanceAwareness>,
Singleton::Consume<I_Messaging>,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_RestApi>
{
public:
TenantManager();
~TenantManager();
void preload() override;
void init() override;
void fini() override;
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __TENANT_MANAGER_H__

View File

@@ -0,0 +1,34 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __TIME_PROXY_H__
#define __TIME_PROXY_H__
#include <memory>
#include "i_time_get.h"
#include "i_time_set.h"
#include "singleton.h"
#include "component.h"
class TimeProxyComponent : public Component, Singleton::Provide<I_TimeGet>, Singleton::Provide<I_TimeSet>
{
public:
TimeProxyComponent();
~TimeProxyComponent();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __TIME_PROXY_H__

View File

@@ -0,0 +1,72 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __TOSTRING_H__
#define __TOSTRING_H__
#include <sstream>
class ToString
{
public:
ToString() {}
template<typename T, typename... Args>
ToString(const T &obj, Args... args)
{
str << obj << static_cast<std::string>(ToString(std::forward<Args>(args)...));
}
template<typename T>
ToString &
operator<<(const T &obj)
{
str << obj;
return *this;
}
template<typename T>
bool
operator==(const T &obj) const
{
return *this == ToString(obj);
}
template<typename T>
bool
operator!=(const T &obj) const
{
return *this != ToString(obj);
}
bool
operator==(const ToString &other) const
{
return str.str() == other.str.str();
}
bool
operator!=(const ToString &other) const
{
return str.str() != other.str.str();
}
void reset() { str.str(""); }
operator std::string() { return str.str(); }
private:
std::ostringstream str;
};
#endif // __TOSTRING_H__