LCOV - code coverage report
Current view: top level - src - endpoint.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 92.7 % 82 76
Test Date: 2026-02-04 14:16:13 Functions: 100.0 % 3 3

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2026 Vinnie Falco (vinnie dot falco at gmail dot com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/cppalliance/corosio
       8              : //
       9              : 
      10              : #include <boost/corosio/endpoint.hpp>
      11              : 
      12              : #include <algorithm>
      13              : #include <charconv>
      14              : 
      15              : namespace boost::corosio {
      16              : 
      17              : endpoint_format
      18           52 : detect_endpoint_format(std::string_view s) noexcept
      19              : {
      20           52 :     if (s.empty())
      21            0 :         return endpoint_format::ipv4_no_port;
      22              : 
      23              :     // Bracketed IPv6
      24           52 :     if (s[0] == '[')
      25           20 :         return endpoint_format::ipv6_bracketed;
      26              : 
      27              :     // Count colons
      28           32 :     std::size_t colon_count = 0;
      29          357 :     for (char c : s)
      30              :     {
      31          325 :         if (c == ':')
      32           32 :             ++colon_count;
      33              :     }
      34              : 
      35           32 :     if (colon_count == 0)
      36            9 :         return endpoint_format::ipv4_no_port;
      37           23 :     if (colon_count == 1)
      38           17 :         return endpoint_format::ipv4_with_port;
      39            6 :     return endpoint_format::ipv6_no_port;
      40              : }
      41              : 
      42              : namespace {
      43              : 
      44              : // Parse port number from string
      45              : // Returns true on success
      46              : bool
      47           26 : parse_port(
      48              :     std::string_view s,
      49              :     std::uint16_t& port) noexcept
      50              : {
      51           26 :     if (s.empty())
      52            4 :         return false;
      53              : 
      54              :     // No leading zeros allowed (except "0" itself)
      55           22 :     if (s.size() > 1 && s[0] == '0')
      56            2 :         return false;
      57              : 
      58           20 :     unsigned long val = 0;
      59           20 :     auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), val);
      60           20 :     if (ec != std::errc{} || ptr != s.data() + s.size())
      61            6 :         return false;
      62           14 :     if (val > 65535)
      63            4 :         return false;
      64              : 
      65           10 :     port = static_cast<std::uint16_t>(val);
      66           10 :     return true;
      67              : }
      68              : 
      69              : } // namespace
      70              : 
      71              : std::error_code
      72           48 : parse_endpoint(
      73              :     std::string_view s,
      74              :     endpoint& ep) noexcept
      75              : {
      76           48 :     if (s.empty())
      77            2 :         return std::make_error_code(std::errc::invalid_argument);
      78              : 
      79           46 :     auto fmt = detect_endpoint_format(s);
      80              : 
      81           46 :     switch (fmt)
      82              :     {
      83            8 :     case endpoint_format::ipv4_no_port:
      84              :     {
      85            8 :         ipv4_address addr;
      86            8 :         auto ec = parse_ipv4_address(s, addr);
      87            8 :         if (ec)
      88            6 :             return ec;
      89            2 :         ep = endpoint(addr, 0);
      90            2 :         return {};
      91              :     }
      92              : 
      93           16 :     case endpoint_format::ipv4_with_port:
      94              :     {
      95              :         // Find the colon separating address and port
      96           16 :         auto colon_pos = s.rfind(':');
      97           16 :         if (colon_pos == std::string_view::npos)
      98            0 :             return std::make_error_code(std::errc::invalid_argument);
      99              : 
     100           16 :         auto addr_str = s.substr(0, colon_pos);
     101           16 :         auto port_str = s.substr(colon_pos + 1);
     102              : 
     103           16 :         ipv4_address addr;
     104           16 :         auto ec = parse_ipv4_address(addr_str, addr);
     105           16 :         if (ec)
     106            0 :             return ec;
     107              : 
     108              :         std::uint16_t port;
     109           16 :         if (!parse_port(port_str, port))
     110           10 :             return std::make_error_code(std::errc::invalid_argument);
     111              : 
     112            6 :         ep = endpoint(addr, port);
     113            6 :         return {};
     114              :     }
     115              : 
     116            4 :     case endpoint_format::ipv6_no_port:
     117              :     {
     118            4 :         ipv6_address addr;
     119            4 :         auto ec = parse_ipv6_address(s, addr);
     120            4 :         if (ec)
     121            0 :             return ec;
     122            4 :         ep = endpoint(addr, 0);
     123            4 :         return {};
     124              :     }
     125              : 
     126           18 :     case endpoint_format::ipv6_bracketed:
     127              :     {
     128              :         // Must start with '[' and contain ']'
     129           18 :         if (s.size() < 2 || s[0] != '[')
     130            2 :             return std::make_error_code(std::errc::invalid_argument);
     131              : 
     132           16 :         auto close_bracket = s.find(']');
     133           16 :         if (close_bracket == std::string_view::npos)
     134            2 :             return std::make_error_code(std::errc::invalid_argument);
     135              : 
     136           14 :         auto addr_str = s.substr(1, close_bracket - 1);
     137              : 
     138           14 :         ipv6_address addr;
     139           14 :         auto ec = parse_ipv6_address(addr_str, addr);
     140           14 :         if (ec)
     141            2 :             return ec;
     142              : 
     143           12 :         std::uint16_t port = 0;
     144           12 :         if (close_bracket + 1 < s.size())
     145              :         {
     146              :             // There's something after ']'
     147           10 :             if (s[close_bracket + 1] != ':')
     148            6 :                 return std::make_error_code(std::errc::invalid_argument);
     149              : 
     150           10 :             auto port_str = s.substr(close_bracket + 2);
     151           10 :             if (!parse_port(port_str, port))
     152            6 :                 return std::make_error_code(std::errc::invalid_argument);
     153              :         }
     154              : 
     155            6 :         ep = endpoint(addr, port);
     156            6 :         return {};
     157              :     }
     158              : 
     159            0 :     default:
     160            0 :         return std::make_error_code(std::errc::invalid_argument);
     161              :     }
     162              : }
     163              : 
     164              : } // namespace boost::corosio
        

Generated by: LCOV version 2.3