src/corosio/src/endpoint.cpp

96.4% Lines (80/83) 100.0% List of functions (4/4) 85.1% Branches (57/67)
endpoint.cpp
f(x) Functions (4)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Vinnie Falco ([email protected])
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 <charconv>
13
14 namespace boost::corosio {
15
16 endpoint_format
17 57x detect_endpoint_format(std::string_view s) noexcept
18 {
19
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 56 times.
57x if (s.empty())
20 1x return endpoint_format::ipv4_no_port;
21
22 // Bracketed IPv6
23
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 36 times.
56x if (s[0] == '[')
24 20x return endpoint_format::ipv6_bracketed;
25
26 // Count colons
27 36x std::size_t colon_count = 0;
28
2/2
✓ Branch 0 taken 374 times.
✓ Branch 1 taken 36 times.
410x for (char c : s)
29 {
30
2/2
✓ Branch 0 taken 338 times.
✓ Branch 1 taken 36 times.
374x if (c == ':')
31 36x ++colon_count;
32 }
33
34
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 10 times.
36x if (colon_count == 0)
35 10x return endpoint_format::ipv4_no_port;
36
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 7 times.
26x if (colon_count == 1)
37 19x return endpoint_format::ipv4_with_port;
38 7x return endpoint_format::ipv6_no_port;
39 57x }
40
41 namespace {
42
43 // Parse port number from string
44 // Returns true on success
45 bool
46 27x parse_port(std::string_view s, std::uint16_t& port) noexcept
47 {
48
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 23 times.
27x if (s.empty())
49 4x return false;
50
51 // No leading zeros allowed (except "0" itself)
52
4/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 2 times.
23x if (s.size() > 1 && s[0] == '0')
53 2x return false;
54
55 21x unsigned long val = 0;
56
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21x auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), val);
57
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
21x if (ec != std::errc{} || ptr != s.data() + s.size())
58 6x return false;
59
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11 times.
15x if (val > 65535)
60 4x return false;
61
62 11x port = static_cast<std::uint16_t>(val);
63 11x return true;
64 27x }
65
66 } // namespace
67
68 static std::error_code
69 52x parse_endpoint_impl(std::string_view s, endpoint& ep) noexcept
70 {
71
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 50 times.
52x if (s.empty())
72 2x return std::make_error_code(std::errc::invalid_argument);
73
74 50x auto fmt = detect_endpoint_format(s);
75
76
4/5
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 18 times.
50x switch (fmt)
77 {
78 case endpoint_format::ipv4_no_port:
79 {
80 9x auto [ec, addr] = make_ipv4_address(s);
81
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9x if (ec)
82 7x return ec;
83 2x ep = endpoint(addr, 0);
84 2x return {};
85 }
86
87 case endpoint_format::ipv4_with_port:
88 {
89 // Find the colon separating address and port
90 18x auto colon_pos = s.rfind(':');
91
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x if (colon_pos == std::string_view::npos)
92 return std::make_error_code(std::errc::invalid_argument);
93
94
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x auto addr_str = s.substr(0, colon_pos);
95
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x auto port_str = s.substr(colon_pos + 1);
96
97 25x auto [ec, addr] = make_ipv4_address(addr_str);
98
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 17 times.
18x if (ec)
99 1x return ec;
100
101 std::uint16_t port;
102
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 10 times.
17x if (!parse_port(port_str, port))
103 10x return std::make_error_code(std::errc::invalid_argument);
104
105 7x ep = endpoint(addr, port);
106 7x return {};
107 }
108
109 case endpoint_format::ipv6_no_port:
110 {
111 5x auto [ec, addr] = make_ipv6_address(s);
112
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4 times.
5x if (ec)
113 1x return ec;
114 4x ep = endpoint(addr, 0);
115 4x return {};
116 }
117
118 case endpoint_format::ipv6_bracketed:
119 {
120 // Must start with '[' and contain ']'
121
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
18x if (s.size() < 2 || s[0] != '[')
122 2x return std::make_error_code(std::errc::invalid_argument);
123
124 16x auto close_bracket = s.find(']');
125
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
16x if (close_bracket == std::string_view::npos)
126 2x return std::make_error_code(std::errc::invalid_argument);
127
128
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14x auto addr_str = s.substr(1, close_bracket - 1);
129
130 20x auto [ec, addr] = make_ipv6_address(addr_str);
131
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14x if (ec)
132 2x return ec;
133
134 12x std::uint16_t port = 0;
135
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
12x if (close_bracket + 1 < s.size())
136 {
137 // There's something after ']'
138
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10x if (s[close_bracket + 1] != ':')
139 return std::make_error_code(std::errc::invalid_argument);
140
141
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10x auto port_str = s.substr(close_bracket + 2);
142
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10x if (!parse_port(port_str, port))
143 6x return std::make_error_code(std::errc::invalid_argument);
144 4x }
145
146 6x ep = endpoint(addr, port);
147 6x return {};
148 }
149
150 default:
151 return std::make_error_code(std::errc::invalid_argument);
152 }
153 52x }
154
155 capy::io_result<endpoint>
156 52x make_endpoint(std::string_view s) noexcept
157 {
158 52x endpoint ep;
159
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 19 times.
52x if (auto ec = parse_endpoint_impl(s, ep))
160 33x return {ec, endpoint{}};
161 19x return {std::error_code{}, ep};
162 52x }
163
164 } // namespace boost::corosio
165