Git Product home page Git Product logo

med's Introduction

Build Coverage License

Meta-Encoder/Decoder

Description

Zero-dependency (STL) header-only C++ library for definition of messages with compile-time generation of corresponding encoder/decoder/printer. MED is extensible library which can be adopted to support many type of encoding rules. Currently it includes:

  • extensible implementation of non-ASN.1 octet encoding rules;
  • incomplete implementation of ASN.1 BER;
  • initial implementation of Google ProtoBuf encoding rules;

See overview for details and samples.

See repos for examples of med usage.

Usage

Define your protocol with MED

#include "med/med.hpp"

template <std::size_t TAG>
using T = med::value<med::fixed<TAG, uint8_t>>;
template <typename ...T>
using M = med::mandatory<T...>;
template <typename ...T>
using O = med::optional<T...>;
using L = med::length_t<med::value<uint8_t>>;

struct BYTE : med::value<uint8_t> {};
struct WORD : med::value<uint16_t> {};
struct TRIBYTE : med::value<med::bytes<3>> {};
struct IP4 : med::value<uint32_t>
{
	static constexpr char const* name() { return "ip-addr"; }
};

struct DWORD : med::value<uint32_t> {};
struct URL : med::octet_string<med::min<5>, med::max<10>>, med::with_snapshot {};

struct MSG1 : med::sequence<
	M< BYTE >,
	M< T<0x21>, WORD >,
	M< L, URL >,
	O< T<0x49>, TRIBYTE >,
	O< T<0x89>, IP4 >,
	O< T<0x03>, DWORD >
>{};

struct MSG2 : med::set<
	M< tag<0x0b>,    BYTE >,
	M< tag<0x21>, L, WORD >,
	O< tag<0x49>, L, TRIBYTE >,
	O< tag<0x89>,    IP4 >,
	O< tag<0x22>, L, URL >
>{};

struct PROTO : med::choice<
	M<T<1>, MSG1>,
	M<T<2>, MSG2>
>{};

Encode

//a buffer to be written with binary data of encoded message
uint8_t buffer[100];
//create encoding context to define input/output/auxiliar
med::encoder_context<> ctx{ buffer };
//the protocol to encode
PROTO proto;
//set particular message in the protocol
auto& msg = proto.ref<MSG2>();
//set particular fields in the message
msg.ref<BYTE>().set(0x12);
msg.ref<WORD>().set(0x3456);
//encode the protocol with octet-encoder into given context
encode(med::octet_encoder{ctx}, proto);
//now the buffer holds encoded message of size ctx.buffer().get_offset()

Decode

//a binary message received in a buffer of size num_bytes
PROTO proto;
med::decoder_context<> ctx;
ctx.reset(buffer, num_bytes);
decode(med::octet_decoder{ctx}, proto);

if (auto const* msg = proto.get<MSG1>())
{
	//read any message field needed
}
else if (auto const* msg = proto.get<MSG2>())
{
	//read any message field needed
}

Print

//decode first (see above)
decode(med::octet_decoder{ctx}, proto);
//use your sink to consume traces, e.g. to print them to console
your_sink sink{};
//trace protocol via your sink
med::print(sink, proto);

Dependencies

Any modern C++ compiler with C++20 support (see CI for the selected ones).

med's People

Contributors

brain5lug avatar cppden avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

brain5lug

med's Issues

Split encode/decode error policy

Provide separate control on error propagation for encoding and decoding.
Default is throw during encode but bool for encode to reduce sensitivity to DoS attacks (see benchmarks).

In dumper need overload to IE_TAG

Add an operator() in the class dumper (printer.hpp) for IE_TAG that is used in print_all()

template <class IE>
constexpr void operator() (IE const& ie, IE_TAG) const noexcept {}

Example:

sink s;
diameter::slh::proto proto;
med2::print_all(s, proto); // error
..

//print all (named and not) IEs in full depth
template <class SINK, class IE, std::size_t MAX_LINE = 128>
void print_all(SINK&& sink, IE const& ie)

Compile error:

cannot convert 'med2::IE_TAG{}' (type 'med2::IE_TAG') to type 'med2::PRIMITIVE'
encoder(ie, IE_TAG{});

Brigand dependency is not mentioned at README

In file included from ../med/med.hpp:9,
from ../ut/ut.hpp:14,
from ../ut/med.cpp:1:
../med/choice.hpp:13:10: fatal error: brigand.hpp: No such file or directory
13 | #include <brigand.hpp>

Add padder_type into printer

public:
	template <class PAD_TRAITS, class FUNC>
	struct padder_type
	{
		constexpr explicit padder_type(FUNC& func) noexcept {}
		static constexpr void enable_padding(bool) noexcept { }
		static constexpr void add_padding() noexcept {}
	};

Example:

gtpu::proto proto;
char const* err = gtpu::decode(data, size, proto);
sink s;
med2::print(s, proto, max_depth); // error

Compile error:

../microcore/gate/rfms/src/msg_dump.cpp:217:13: required from here
../microcore/common/codec/med2/encode.hpp:274:47: error: no class template named 'padder_type' in 'class med2::printer<sink_t<100000>&, 128>'
274 | using pad_t = typename ENCODER::template padder_type<pad_traits, ENCODER>;

not detecting malformed IE

when exceptions are used for error reporting and malformed IE appears inside length constrained sequence the exception will be caught and treated as end of sequence.
need to introduce typed exceptions to resolve this but 1st include UT to detect such case.

Fix for ascii_string when char array is used as a source

Денис, привет.

В продолжение нашего разговора, оставляю обновление для ascii_string. Предлагаю добавить этот метод в выше упомянутый класс.

template <std::size_t N>
bool set(char const(&arr)[N]) { return this->set_encoded(std::strlen(arr), arr); }

Тест для этого случая

TEST(common, ascii_string_set)
{
	char arr[8] = {0};
	strcpy(arr, "str");
	med2::ascii_string s;
	s.set(arr);
	EXPECT_EQ(s.get().size(), strlen(arr));
}

Optional with default value

extend mandatory (optional?) with condition and default value for example to describe GTP-C message priority.

Bug with encoding multi-field with condition.

while (typename IE::condition{}(to));

Case:

struct MySeq : med::sequence<
    M<Flag>,
    O<Case1, Flag::is_case1>, // is_case1 returns true if Flag.get() == 1
    O<Case2, Flag::is_case2, med::inf>// is_case1 returns true if Flag.get() == 2
>
struct Msg : med::sequence<
    M<L, MySeq>
>
{
};

Decoder will try to decode Case2 until the end of Msg, but not end of MySeq with specified length. Probably, it happens because the loop

while (typename IE::condition{}(to));

doesn't check decoder(CHECK_STATE{}, ie) and IE::condition{}(to) return constant value for specific Msg. So loop ends only when decoding one more Case2 fails.

padding as meta-info at IE level

now padding is only supported in container but should be available for single IE with length (e.g. like in RTCP User-Id).

padding also s.b. defined via meta-info

Non-const iterators for multi-field IEs containers

to avoid complicated constructions in the code like:

auto& teps = m_data.ref<udsp::smf::qos_info>().ref<udsp::smf::traffic_endpoints>();
    for (auto& tep : teps.get())
    {
        if (!tep.get<udsp::smf::valid>().get())
        {
            udsp::smf::traffic_endpoint& nc_tep = const_cast<udsp::smf::traffic_endpoint&>(tep);
            nc_tep.ref<udsp::smf::local_f_teid>().clear();
            nc_tep.ref<udsp::smf::network_instance>().clear();
            return &nc_tep;
        }
    }

reduce code bloat

possible to use type-erasure at some common functions to reduce code bloat

Bug with decoding a sequence of optionals with unique tags

Test:

#include "ut.hpp"
#include "ut_proto.hpp"

struct o_params : med::sequence<
        O<C<0x01>, FLD_UC>,
        O<C<0x02>, FLD_U8>,
        O<C<0x03>, FLD_U16>>
{
};

struct m_params : med::sequence<
        M<FLD_UC>,
        M<FLD_U8>,
        M<FLD_U16>>
{
};

struct params : med::sequence<
        M<FLD_U8>,
        O<C<0x04>, o_params>,
        O<C<0x05>, m_params>>
{

};


TEST(sequence, optional)
{
    params p1;

    p1.ref<FLD_U8>().set(0);

    p1.ref<o_params>().ref<FLD_U8>().set(1);

    p1.ref<m_params>().ref<FLD_UC>().set(2);
    p1.ref<m_params>().ref<FLD_U8>().set(3);
    p1.ref<m_params>().ref<FLD_U16>().set(4);

    uint8_t e_buffer[64];
    med::encoder_context e_ctx{e_buffer};
    encode(med::octet_encoder{e_ctx}, p1);

    uint8_t d_buffer[64];
    med::allocator d_alloc{d_buffer};
    med::decoder_context<med::allocator> d_ctx{e_ctx.buffer().get_start(), e_ctx.buffer().get_offset(), &d_alloc};
    params p2;
    med::decode(med::octet_decoder{d_ctx}, p2);

    EXPECT_NE(p2.get<m_params>(), nullptr);
}

Adding length to o_params fixes the problem (O<C<0x04>, L, o_params>) .

clear for choice

clear in choice only resets the header w/o clearing currently selected value

typelist with foreach

seems to be possible to factor out loops in one template, put ies in typelist and iterate with functor instead of multiple crafted loops.

align allocator with std::pmr

perhaps it's worth to have the same interface as std::pmr::memory_resource to allow use of any external allocators

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.