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
24using AddressV4 = USERVER_NAMESPACE::
utils::ip::AddressV4;
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;
44inline constexpr bool kIsNetworkType = std::is_same_v<T, USERVER_NAMESPACE::utils::ip::NetworkV4> ||
45 std::is_same_v<T, USERVER_NAMESPACE::utils::ip::NetworkV6>;
48inline constexpr bool kIsAddressType = std::is_same_v<T, USERVER_NAMESPACE::utils::ip::AddressV4> ||
49 std::is_same_v<T, USERVER_NAMESPACE::utils::ip::AddressV6>;
52struct IpBufferFormatterBase : BufferFormatterBase<T> {
54 using BaseType = BufferFormatterBase<T>;
55 using BaseType::BaseType;
56 template <
typename Address>
57 struct IpFormatterInfo {
59 char address_family =
'\0';
60 char prefix_length =
'\0';
64 template <
typename Buffer,
typename Address>
65 void Format(IpFormatterInfo<Address> info,
const UserTypes& types, Buffer& buffer) {
66 buffer.reserve(buffer.size() + info.address.size() + 4);
67 io::WriteBuffer(types, buffer, info.address_family);
68 io::WriteBuffer(types, buffer, info.prefix_length);
69 io::WriteBuffer(types, buffer, info.is_cidr);
70 io::WriteBuffer(types, buffer,
static_cast<
char>(info.address.size()));
71 for (
const auto val : info.address) {
72 io::WriteBuffer(types, buffer,
static_cast<
char>(val));
77template <
typename T,
typename = std::enable_if_t<kIsAddressType<T>>>
78struct AddressNetworkBuffer : IpBufferFormatterBase<T> {
79 using BaseType = IpBufferFormatterBase<T>;
80 using BaseType::BaseType;
82 template <
typename Buffer>
83 void operator()(
const UserTypes& types, Buffer& buffer) {
84 using Address =
typename T::BytesType;
85 constexpr bool is_address_v4 = std::is_same_v<T, USERVER_NAMESPACE::
utils::ip::AddressV4>;
86 typename BaseType::
template IpFormatterInfo<Address> info{
87 this->value.GetBytes(),
88 is_address_v4 ? kPgsqlAfInet : kPgsqlAfInet6,
90 static_cast<
char>(is_address_v4 ? NetworkV4::kMaximumPrefixLength : NetworkV6::kMaximumPrefixLength),
92 BaseType::Format(info, types, buffer);
96template <
typename T,
typename = std::enable_if_t<kIsNetworkType<T>>>
97struct NetworkBufferFormatter : IpBufferFormatterBase<T> {
98 using BaseType = IpBufferFormatterBase<T>;
99 using BaseType::BaseType;
101 template <
typename Buffer>
102 void operator()(
const UserTypes& types, Buffer& buffer) {
103 using Address =
typename T::AddressType::BytesType;
104 const auto canonical_network = USERVER_NAMESPACE::utils::ip::TransformToCidrFormat(
this->value);
105 if (canonical_network !=
this->value) {
106 throw IpAddressInvalidFormat(
107 "Network expected CIDR format. Use utils::ip::TransformToCidrFormat "
108 "method to conversation."
111 typename BaseType::
template IpFormatterInfo<Address> info{
112 canonical_network.GetAddress().GetBytes(),
114 std::is_same_v<T, USERVER_NAMESPACE::utils::ip::NetworkV4> ? kPgsqlAfInet : kPgsqlAfInet6,
116 static_cast<
char>(canonical_network.GetPrefixLength()),
118 BaseType::Format(info, types, buffer);
123struct IpBufferParserBase : BufferParserBase<T> {
125 using BaseType = BufferParserBase<T>;
126 using BaseType::BaseType;
128 template <
typename Bytes>
129 struct IpParserInfo {
131 unsigned char family =
'\0';
132 unsigned char prefix_length =
'\0';
133 unsigned char is_cidr =
'\0';
134 unsigned char bytes_number =
'\0';
137 template <
typename Bytes>
139 IpParserInfo<Bytes> result;
140 const uint8_t* byte_cptr = buffer.buffer;
141 result.family = *byte_cptr;
143 result.prefix_length = *byte_cptr;
145 result.is_cidr = *byte_cptr;
147 result.bytes_number = *byte_cptr;
149 this->ParseIpBytes(byte_cptr, result.bytes, result.bytes_number, result.family);
156 const uint8_t* byte_cptr,
157 std::array<
unsigned char, N>& bytes,
158 unsigned char bytes_number,
161 if (bytes_number != bytes.size()) {
163 fmt::format(
"Expected address size is {}, actual is {}", bytes_number, bytes.size())
166 std::memcpy(bytes.data(), byte_cptr, bytes.size());
170 const uint8_t* byte_cptr,
171 std::vector<
unsigned char>& bytes,
172 unsigned char bytes_number,
173 unsigned char address_family
175 if (!(bytes_number == 16 && address_family == kPgsqlAfInet6) &&
176 !(bytes_number == 4 && address_family == kPgsqlAfInet)) {
177 throw storages::postgres::IpAddressInvalidFormat(
"Invalid INET format");
179 bytes.resize(bytes_number);
180 std::memcpy(bytes.data(), byte_cptr, bytes_number);
184template <
typename T,
typename = std::enable_if_t<kIsNetworkType<T>>>
185struct NetworkBufferParser : IpBufferParserBase<T> {
186 using BaseType = IpBufferParserBase<T>;
187 using BaseType::BaseType;
190 using Address =
typename T::AddressType;
191 using Bytes =
typename Address::BytesType;
192 const auto info = BaseType::
template Parse<Bytes>(buffer);
193 constexpr auto expected_family = std::is_same_v<T, NetworkV4> ? kPgsqlAfInet : kPgsqlAfInet6;
194 if (info.family != expected_family) {
195 throw storages::postgres::IpAddressInvalidFormat(
"Actual address family doesn't supported for type");
197 if (info.is_cidr != kIsCidr) {
198 throw storages::postgres::IpAddressInvalidFormat(
"Network isn't in CIDR format");
200 this->value = T(Address(info.bytes), info.prefix_length);
204template <
typename T,
typename = std::enable_if_t<kIsAddressType<T>>>
205struct AddressBufferParser : detail::IpBufferParserBase<T> {
206 using BaseType = detail::IpBufferParserBase<T>;
207 using BaseType::BaseType;
210 using Bytes =
typename T::BytesType;
211 const auto info = BaseType::
template Parse<Bytes>(buffer);
212 constexpr auto expected_family = std::is_same_v<T, AddressV4> ? kPgsqlAfInet : kPgsqlAfInet6;
213 if (info.family != expected_family) {
214 throw storages::postgres::IpAddressInvalidFormat(
"Actual address family doesn't supported for type");
216 constexpr unsigned char expected_prefix_length =
217 std::is_same_v<T, AddressV4> ? NetworkV4::kMaximumPrefixLength : NetworkV6::kMaximumPrefixLength;
218 if (info.prefix_length != expected_prefix_length) {
220 "Expected prefix length is {}, actual prefix is {}",
221 static_cast<
int>(expected_prefix_length),
222 static_cast<
int>(info.prefix_length)
225 if (info.is_cidr != kIsCidr) {
226 throw storages::postgres::IpAddressInvalidFormat(
"Network isn't in CIDR format");
228 this->value = T(info.bytes);
272 template <
typename Buffer>
342struct CppToSystemPg<AddressV6> : PredefinedOid<PredefinedOids::kCidr> {};
344struct CppToSystemPg<AddressV4> : PredefinedOid<PredefinedOids::kCidr> {};
346struct CppToSystemPg<InetNetwork> : PredefinedOid<PredefinedOids::kInet> {};