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 =
 
   45    std::is_same_v<T, USERVER_NAMESPACE::utils::ip::NetworkV4> ||
 
   46    std::is_same_v<T, USERVER_NAMESPACE::utils::ip::NetworkV6>;
 
   49inline constexpr bool kIsAddressType =
 
   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,
 
   69    buffer.reserve(buffer.size() + info.address.size() + 4);
 
   70    io::WriteBuffer(types, buffer, info.address_family);
 
   71    io::WriteBuffer(types, buffer, info.prefix_length);
 
   72    io::WriteBuffer(types, buffer, info.is_cidr);
 
   73    io::WriteBuffer(types, buffer, 
static_cast<
char>(info.address.size()));
 
   74    for (
const auto val : info.address) {
 
   75      io::WriteBuffer(types, buffer, 
static_cast<
char>(val));
 
   80template <
typename T, 
typename = std::enable_if_t<kIsAddressType<T>>>
 
   81struct AddressNetworkBuffer : IpBufferFormatterBase<T> {
 
   82  using BaseType = IpBufferFormatterBase<T>;
 
   83  using BaseType::BaseType;
 
   85  template <
typename Buffer>
 
   86  void operator()(
const UserTypes& types, Buffer& buffer) {
 
   87    using Address = 
typename T::BytesType;
 
   88    constexpr bool is_address_v4 =
 
   89        std::is_same_v<T, USERVER_NAMESPACE::utils::ip::AddressV4>;
 
   90    typename BaseType::
template IpFormatterInfo<Address> info{
 
   91         this->value.GetBytes(),
 
   92         is_address_v4 ? kPgsqlAfInet : kPgsqlAfInet6,
 
   94        static_cast<
char>(is_address_v4 ? NetworkV4::kMaximumPrefixLength
 
   95                                        : NetworkV6::kMaximumPrefixLength),
 
   97    BaseType::Format(info, types, buffer);
 
  101template <
typename T, 
typename = std::enable_if_t<kIsNetworkType<T>>>
 
  102struct NetworkBufferFormatter : IpBufferFormatterBase<T> {
 
  103  using BaseType = IpBufferFormatterBase<T>;
 
  104  using BaseType::BaseType;
 
  106  template <
typename Buffer>
 
  107  void operator()(
const UserTypes& types, Buffer& buffer) {
 
  108    using Address = 
typename T::AddressType::BytesType;
 
  109    const auto canonical_network =
 
  110        USERVER_NAMESPACE::utils::ip::TransformToCidrFormat(
this->value);
 
  111    if (canonical_network != 
this->value) {
 
  112      throw IpAddressInvalidFormat(
 
  113          "Network expected CIDR format. Use utils::ip::TransformToCidrFormat " 
  114          "method to conversation.");
 
  116    typename BaseType::
template IpFormatterInfo<Address> info{
 
  117         canonical_network.GetAddress().GetBytes(),
 
  119        std::is_same_v<T, USERVER_NAMESPACE::utils::ip::NetworkV4>
 
  123        static_cast<
char>(canonical_network.GetPrefixLength()),
 
  125    BaseType::Format(info, types, buffer);
 
  130struct IpBufferParserBase : BufferParserBase<T> {
 
  132  using BaseType = BufferParserBase<T>;
 
  133  using BaseType::BaseType;
 
  135  template <
typename Bytes>
 
  136  struct IpParserInfo {
 
  138    unsigned char family = 
'\0';
 
  139    unsigned char prefix_length = 
'\0';
 
  140    unsigned char is_cidr = 
'\0';
 
  141    unsigned char bytes_number = 
'\0';
 
  144  template <
typename Bytes>
 
  146    IpParserInfo<Bytes> result;
 
  147    const uint8_t* byte_cptr = buffer.buffer;
 
  148    result.family = *byte_cptr;
 
  150    result.prefix_length = *byte_cptr;
 
  152    result.is_cidr = *byte_cptr;
 
  154    result.bytes_number = *byte_cptr;
 
  156    this->ParseIpBytes(byte_cptr, result.bytes, result.bytes_number,
 
  163  void ParseIpBytes(
const uint8_t* byte_cptr,
 
  164                    std::array<
unsigned char, N>& bytes,
 
  165                    unsigned char bytes_number, 
unsigned char) {
 
  166    if (bytes_number != bytes.size()) {
 
  167      throw storages::postgres::IpAddressInvalidFormat(
 
  168          fmt::format(
"Expected address size is {}, actual is {}", bytes_number,
 
  171    std::memcpy(bytes.data(), byte_cptr, bytes.size());
 
  174  void ParseIpBytes(
const uint8_t* byte_cptr, std::vector<
unsigned char>& bytes,
 
  175                    unsigned char bytes_number, 
unsigned char address_family) {
 
  176    if (!(bytes_number == 16 && address_family == kPgsqlAfInet6) &&
 
  177        !(bytes_number == 4 && address_family == kPgsqlAfInet)) {
 
  178      throw storages::postgres::IpAddressInvalidFormat(
"Invalid INET format");
 
  180    bytes.resize(bytes_number);
 
  181    std::memcpy(bytes.data(), byte_cptr, bytes_number);
 
  185template <
typename T, 
typename = std::enable_if_t<kIsNetworkType<T>>>
 
  186struct NetworkBufferParser : IpBufferParserBase<T> {
 
  187  using BaseType = IpBufferParserBase<T>;
 
  188  using BaseType::BaseType;
 
  191    using Address = 
typename T::AddressType;
 
  192    using Bytes = 
typename Address::BytesType;
 
  193    const auto info = BaseType::
template Parse<Bytes>(buffer);
 
  194    constexpr auto expected_family =
 
  195        std::is_same_v<T, NetworkV4> ? kPgsqlAfInet : kPgsqlAfInet6;
 
  196    if (info.family != expected_family) {
 
  197      throw storages::postgres::IpAddressInvalidFormat(
 
  198          "Actual address family doesn't supported for type");
 
  200    if (info.is_cidr != kIsCidr) {
 
  201      throw storages::postgres::IpAddressInvalidFormat(
 
  202          "Network isn't in CIDR format");
 
  204    this->value = T(Address(info.bytes), info.prefix_length);
 
  208template <
typename T, 
typename = std::enable_if_t<kIsAddressType<T>>>
 
  209struct AddressBufferParser : detail::IpBufferParserBase<T> {
 
  210  using BaseType = detail::IpBufferParserBase<T>;
 
  211  using BaseType::BaseType;
 
  214    using Bytes = 
typename T::BytesType;
 
  215    const auto info = BaseType::
template Parse<Bytes>(buffer);
 
  216    constexpr auto expected_family =
 
  217        std::is_same_v<T, AddressV4> ? kPgsqlAfInet : kPgsqlAfInet6;
 
  218    if (info.family != expected_family) {
 
  219      throw storages::postgres::IpAddressInvalidFormat(
 
  220          "Actual address family doesn't supported for type");
 
  222    constexpr unsigned char expected_prefix_length =
 
  223        std::is_same_v<T, AddressV4> ? NetworkV4::kMaximumPrefixLength
 
  224                                     : NetworkV6::kMaximumPrefixLength;
 
  225    if (info.prefix_length != expected_prefix_length) {
 
  226      throw storages::postgres::IpAddressInvalidFormat(
 
  227          fmt::format(
"Expected prefix length is {}, actual prefix is {}",
 
  228                      static_cast<
int>(expected_prefix_length),
 
  229                      static_cast<
int>(info.prefix_length)));
 
  231    if (info.is_cidr != kIsCidr) {
 
  232      throw storages::postgres::IpAddressInvalidFormat(
 
  233          "Network isn't in CIDR format");
 
  235    this->value = T(info.bytes);
 
  280  template <
typename Buffer>
 
  350struct CppToSystemPg<AddressV6> : PredefinedOid<PredefinedOids::kCidr> {};
 
  352struct CppToSystemPg<AddressV4> : PredefinedOid<PredefinedOids::kCidr> {};
 
  354struct CppToSystemPg<InetNetwork> : PredefinedOid<PredefinedOids::kInet> {};