9#include <userver/storages/postgres/io/buffer_io.hpp>
10#include <userver/storages/postgres/io/buffer_io_base.hpp>
11#include <userver/storages/postgres/io/integral_types.hpp>
12#include <userver/storages/postgres/io/string_types.hpp>
13#include <userver/storages/postgres/io/type_mapping.hpp>
14#include <userver/utils/ip.hpp>
16USERVER_NAMESPACE_BEGIN
21using NetworkV4 = USERVER_NAMESPACE::
utils::
ip::NetworkV4;
24using AddressV4 = USERVER_NAMESPACE::
utils::
ip::AddressV4;
26using NetworkV6 = USERVER_NAMESPACE::
utils::
ip::NetworkV6;
28using AddressV6 = USERVER_NAMESPACE::
utils::
ip::AddressV6;
30using InetNetwork = USERVER_NAMESPACE::
utils::
ip::InetNetwork;
36inline constexpr char kPgsqlAfInet = AF_INET + 0;
37inline constexpr char kPgsqlAfInet6 = AF_INET + 1;
40inline constexpr char kIsCidr = 1;
41inline constexpr char kIsInet = 0;
45 std::is_same_v<T, USERVER_NAMESPACE::
utils::
ip::NetworkV4> ||
46 std::is_same_v<T, USERVER_NAMESPACE::
utils::
ip::NetworkV6>;
50 std::is_same_v<T, USERVER_NAMESPACE::
utils::
ip::AddressV4> ||
51 std::is_same_v<T, USERVER_NAMESPACE::
utils::
ip::AddressV6>;
54struct IpBufferFormatterBase : BufferFormatterBase<T> {
56 using BaseType = BufferFormatterBase<T>;
57 using BaseType::BaseType;
58 template <
typename Address>
59 struct IpFormatterInfo {
61 char address_family =
'\0';
62 char prefix_length =
'\0';
66 template <
typename Buffer,
typename Address>
67 void Format(IpFormatterInfo<Address> info,
const UserTypes& types, Buffer& buffer) {
68 buffer.reserve(buffer.size() + info.address.size() + 4);
69 io::WriteBuffer(types, buffer, info.address_family);
70 io::WriteBuffer(types, buffer, info.prefix_length);
71 io::WriteBuffer(types, buffer, info.is_cidr);
72 io::WriteBuffer(types, buffer,
static_cast<
char>(info.address.size()));
73 for (
const auto val : info.address) {
74 io::WriteBuffer(types, buffer,
static_cast<
char>(val));
79template <AddressType T>
80struct AddressNetworkBuffer : IpBufferFormatterBase<T> {
81 using BaseType = IpBufferFormatterBase<T>;
82 using BaseType::BaseType;
84 template <
typename Buffer>
85 void operator()(
const UserTypes& types, Buffer& buffer) {
86 using Address =
typename T::BytesType;
87 constexpr bool kIsAddressV4 = std::is_same_v<T, USERVER_NAMESPACE::
utils::
ip::AddressV4>;
88 const typename BaseType::
template IpFormatterInfo<Address> info{
89 this->value.GetBytes(),
90 kIsAddressV4 ? kPgsqlAfInet : kPgsqlAfInet6,
92 static_cast<
char>(kIsAddressV4 ? NetworkV4::kMaximumPrefixLength : NetworkV6::kMaximumPrefixLength),
95 BaseType::Format(info, types, buffer);
99template <NetworkType T>
100struct NetworkBufferFormatter : IpBufferFormatterBase<T> {
101 using BaseType = IpBufferFormatterBase<T>;
102 using BaseType::BaseType;
104 template <
typename Buffer>
105 void operator()(
const UserTypes& types, Buffer& buffer) {
106 using Address =
typename T::AddressType::BytesType;
107 const auto canonical_network = USERVER_NAMESPACE::
utils::
ip::TransformToCidrFormat(
this->value);
108 if (canonical_network !=
this->value) {
110 "Network expected CIDR format. Use utils::ip::TransformToCidrFormat "
111 "method to conversation."
114 const typename BaseType::
template IpFormatterInfo<Address> info{
115 canonical_network.GetAddress().GetBytes(),
117 std::is_same_v<T, USERVER_NAMESPACE::
utils::
ip::NetworkV4> ? kPgsqlAfInet : kPgsqlAfInet6,
119 static_cast<
char>(canonical_network.GetPrefixLength()),
122 BaseType::Format(info, types, buffer);
127struct IpBufferParserBase : BufferParserBase<T> {
129 using BaseType = BufferParserBase<T>;
130 using BaseType::BaseType;
132 template <
typename Bytes>
133 struct IpParserInfo {
135 unsigned char family =
'\0';
136 unsigned char prefix_length =
'\0';
137 unsigned char is_cidr =
'\0';
138 unsigned char bytes_number =
'\0';
141 template <
typename Bytes>
143 static constexpr std::size_t kHeaderSize = 4;
146 if (buffer.length < kHeaderSize) {
148 fmt::format(
"Buffer size {} is too small to parse an IP address", buffer.length)
151 IpParserInfo<Bytes> result;
152 const uint8_t* byte_cptr = buffer.buffer;
153 result.family = *byte_cptr;
155 result.prefix_length = *byte_cptr;
157 result.is_cidr = *byte_cptr;
159 result.bytes_number = *byte_cptr;
161 if (buffer.length - kHeaderSize < result.bytes_number) {
163 "Buffer size {} is too small for an IP address of {} bytes",
168 this->ParseIpBytes(byte_cptr, result.bytes, result.bytes_number, result.family);
175 const uint8_t* byte_cptr,
176 std::array<
unsigned char, N>& bytes,
177 unsigned char bytes_number,
180 if (bytes_number != bytes.size()) {
182 fmt::format(
"Expected address size is {}, actual is {}", bytes_number, bytes.size())
185 std::memcpy(bytes.data(), byte_cptr, bytes.size());
189 const uint8_t* byte_cptr,
190 std::vector<
unsigned char>& bytes,
191 unsigned char bytes_number,
192 unsigned char address_family
194 if (!(bytes_number == 16 && address_family == kPgsqlAfInet6) &&
195 !(bytes_number == 4 && address_family == kPgsqlAfInet))
199 bytes.resize(bytes_number);
200 std::memcpy(bytes.data(), byte_cptr, bytes_number);
204template <NetworkType T>
205struct NetworkBufferParser : IpBufferParserBase<T> {
206 using BaseType = IpBufferParserBase<T>;
207 using BaseType::BaseType;
210 using Address =
typename T::AddressType;
211 using Bytes =
typename Address::BytesType;
212 const auto info = BaseType::
template Parse<Bytes>(buffer);
213 constexpr auto expected_family = std::is_same_v<T, NetworkV4> ? kPgsqlAfInet : kPgsqlAfInet6;
214 if (info.family != expected_family) {
217 if (info.is_cidr != kIsCidr) {
220 this->value = T(Address(info.bytes), info.prefix_length);
224template <AddressType T>
225struct AddressBufferParser : detail::IpBufferParserBase<T> {
226 using BaseType = detail::IpBufferParserBase<T>;
227 using BaseType::BaseType;
230 using Bytes =
typename T::BytesType;
231 const auto info = BaseType::
template Parse<Bytes>(buffer);
232 constexpr auto expected_family = std::is_same_v<T, AddressV4> ? kPgsqlAfInet : kPgsqlAfInet6;
233 if (info.family != expected_family) {
236 constexpr unsigned char expected_prefix_length =
237 std::is_same_v<T, AddressV4> ? NetworkV4::kMaximumPrefixLength : NetworkV6::kMaximumPrefixLength;
238 if (info.prefix_length != expected_prefix_length) {
240 "Expected prefix length is {}, actual prefix is {}",
241 static_cast<
int>(expected_prefix_length),
242 static_cast<
int>(info.prefix_length)
245 if (info.is_cidr != kIsCidr) {
248 this->value = T(info.bytes);
256struct BufferFormatter<NetworkV4> : detail::NetworkBufferFormatter<NetworkV4> {
257 using BaseType = detail::NetworkBufferFormatter<NetworkV4>;
259 using BaseType::BaseType;
264struct BufferFormatter<NetworkV6> : detail::NetworkBufferFormatter<NetworkV6> {
265 using BaseType = detail::NetworkBufferFormatter<NetworkV6>;
267 using BaseType::BaseType;
272struct BufferFormatter<AddressV4> : detail::AddressNetworkBuffer<AddressV4> {
273 using BaseType = detail::AddressNetworkBuffer<AddressV4>;
275 using BaseType::BaseType;
280struct BufferFormatter<AddressV6> : detail::AddressNetworkBuffer<AddressV6> {
281 using BaseType = detail::AddressNetworkBuffer<AddressV6>;
283 using BaseType::BaseType;
288struct BufferFormatter<InetNetwork> : detail::IpBufferFormatterBase<InetNetwork> {
289 using BaseType = detail::IpBufferFormatterBase<InetNetwork>;
290 using BaseType::BaseType;
292 template <
typename Buffer>
293 void operator()(
const UserTypes& types, Buffer& buffer) {
294 using Address = std::vector<
unsigned char>;
295 const typename BaseType::
template IpFormatterInfo<Address> info{
299 ? detail::kPgsqlAfInet
300 : detail::kPgsqlAfInet6,
304 BaseType::Format(info, types, buffer);
310struct BufferParser<NetworkV4> : detail::NetworkBufferParser<NetworkV4> {
311 using BaseType = detail::NetworkBufferParser<NetworkV4>;
313 using BaseType::BaseType;
318struct BufferParser<NetworkV6> : detail::NetworkBufferParser<NetworkV6> {
319 using BaseType = detail::NetworkBufferParser<NetworkV6>;
321 using BaseType::BaseType;
326struct BufferParser<AddressV4> : detail::AddressBufferParser<AddressV4> {
327 using BaseType = detail::AddressBufferParser<AddressV4>;
329 using BaseType::BaseType;
334struct BufferParser<AddressV6> : detail::AddressBufferParser<AddressV6> {
335 using BaseType = detail::AddressBufferParser<AddressV6>;
337 using BaseType::BaseType;
342struct BufferParser<InetNetwork> : detail::IpBufferParserBase<InetNetwork> {
343 using BaseType = detail::IpBufferParserBase<InetNetwork>;
344 using BaseType::BaseType;
347 using Bytes = std::vector<
unsigned char>;
348 auto info = BaseType::
template Parse<Bytes>(buffer);
349 this->value = InetNetwork(
350 std::move(info.bytes),
352 (info.family == detail::kPgsqlAfInet ? InetNetwork::AddressFamily::kIPv4 : InetNetwork::AddressFamily::kIPv6