Skip to content

Commit b90cfe5

Browse files
BonnyAD9sedmicha
authored andcommitted
TCP - Add decoder factory
1 parent 9297b1f commit b90cfe5

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

src/plugins/input/tcp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_library(tcp-input MODULE
99
src/ClientManager.cpp
1010
src/IpfixDecoder.cpp
1111
src/Lz4Decoder.cpp
12+
src/DecoderFactory.cpp
1213
)
1314

1415
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_HOST_SYSTEM_NAME STREQUAL "OpenBSD")
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* \file
3+
* \author Jakub Antonín Štigler <[email protected]>
4+
* \brief Factory for creating decoders (source file)
5+
* \date 2024
6+
*
7+
* Copyright: (C) 2023 CESNET, z.s.p.o.
8+
* SPDX-License-Identifier: BSD-3-Clause
9+
*/
10+
11+
#include "DecoderFactory.hpp"
12+
13+
#include <memory> // unique_ptr
14+
#include <array> // array
15+
#include <cstdint> // uint8_t, uint16_t
16+
#include <stdexcept> // runtime_error
17+
#include <cerrno> // errno
18+
#include <string> // string
19+
#include <cstddef> // size_t
20+
21+
#include <sys/socket.h> // recv, MSG_PEEK, MSG_WAITALL
22+
#include <netinet/in.h> // ntohl, ntohs
23+
24+
#include <ipfixcol2.h> // ipx_strerror
25+
26+
#include "Decoder.hpp" // Decoder
27+
#include "Lz4Decoder.hpp" // LZ4_MAGIC, Lz4Decoder
28+
#include "IpfixDecoder.hpp" // IPFIX_MAGIC, IpfixDecoder
29+
30+
#include <iostream>
31+
32+
namespace tcp_in {
33+
34+
DecoderFactory::DecoderFactory() {};
35+
36+
std::unique_ptr<Decoder> DecoderFactory::detect_decoder(int fd) {
37+
// number of bytes neaded to detect the decoder
38+
constexpr size_t MAX_MAGIC_LEN = 4;
39+
40+
std::array<uint8_t, MAX_MAGIC_LEN> buf{};
41+
42+
auto res = recv(fd, buf.begin(), buf.size(), MSG_PEEK | MSG_WAITALL);
43+
if (res == -1) {
44+
const char *err_msg;
45+
ipx_strerror(errno, err_msg);
46+
throw std::runtime_error("Failed to receive start of first message: " + std::string(err_msg));
47+
}
48+
49+
constexpr const char *not_enough_data_err =
50+
"Failed to read enough bytes to recognize the decoder";
51+
52+
// check decoders in order from shortest magic number to longest
53+
54+
if (res < 2) {
55+
throw std::runtime_error(not_enough_data_err);
56+
}
57+
58+
// IPFIX decoder
59+
auto magic_u16 = ntohs(*reinterpret_cast<uint16_t *>(buf.begin()));
60+
if (magic_u16 == IPFIX_MAGIC) {
61+
return create_ipfix_decoder(fd);
62+
}
63+
64+
if (res < 4) {
65+
throw std::runtime_error(not_enough_data_err);
66+
}
67+
68+
// LZ4 decoder
69+
auto magic_u32 = ntohl(*reinterpret_cast<uint32_t *>(buf.begin()));
70+
if (magic_u32 == LZ4_MAGIC) {
71+
return create_lz4_decoder(fd);
72+
}
73+
74+
throw std::runtime_error("Failed to recognize the decoder.");
75+
}
76+
77+
std::unique_ptr<Decoder> DecoderFactory::create_ipfix_decoder(int fd) {
78+
return std::unique_ptr<Decoder>(new IpfixDecoder(fd));
79+
}
80+
81+
std::unique_ptr<Decoder> DecoderFactory::create_lz4_decoder(int fd) {
82+
return std::unique_ptr<Decoder>(new Lz4Decoder(fd));
83+
}
84+
85+
} // namespace tcp_in
86+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* \file
3+
* \author Jakub Antonín Štigler <[email protected]>
4+
* \brief Factory for creating decoders (header file)
5+
* \date 2024
6+
*
7+
* Copyright: (C) 2023 CESNET, z.s.p.o.
8+
* SPDX-License-Identifier: BSD-3-Clause
9+
*/
10+
11+
#pragma once
12+
13+
#include <memory> // std::unique_ptr
14+
15+
#include "Decoder.hpp" // Decoder
16+
17+
namespace tcp_in {
18+
19+
/** Factory for TCP decoders. */
20+
class DecoderFactory {
21+
public:
22+
DecoderFactory();
23+
24+
/**
25+
* @brief Detects the type of decoder that should be used to decode the given stream and
26+
* constructs it. This function may block if the decoder cannot be determined without recieving
27+
* more data.
28+
* @param fd TCP stream file descriptor
29+
* @return Instance of the correct decoder, nullptr no decoder matches the data.
30+
*/
31+
std::unique_ptr<Decoder> detect_decoder(int fd);
32+
33+
private:
34+
std::unique_ptr<Decoder> create_ipfix_decoder(int fd);
35+
std::unique_ptr<Decoder> create_lz4_decoder(int fd);
36+
};
37+
38+
} // namespace tcp_in

0 commit comments

Comments
 (0)