TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2026 Michael Vandeberg
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/corosio
9 : //
10 :
11 : #ifndef BOOST_COROSIO_IPV4_ADDRESS_HPP
12 : #define BOOST_COROSIO_IPV4_ADDRESS_HPP
13 :
14 : #include <boost/corosio/detail/config.hpp>
15 :
16 : #include <boost/capy/io_result.hpp>
17 :
18 : #include <array>
19 : #include <compare>
20 : #include <cstdint>
21 : #include <functional>
22 : #include <iosfwd>
23 : #include <string>
24 : #include <string_view>
25 : #include <system_error>
26 :
27 : namespace boost::corosio {
28 :
29 : /** An IP version 4 style address.
30 :
31 : Objects of this type are used to construct,
32 : parse, and manipulate IP version 4 addresses.
33 :
34 : @par BNF
35 : @code
36 : IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
37 :
38 : dec-octet = DIGIT ; 0-9
39 : / %x31-39 DIGIT ; 10-99
40 : / "1" 2DIGIT ; 100-199
41 : / "2" %x30-34 DIGIT ; 200-249
42 : / "25" %x30-35 ; 250-255
43 : @endcode
44 :
45 : @par Specification
46 : @li <a href="https://en.wikipedia.org/wiki/IPv4">IPv4 (Wikipedia)</a>
47 : @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
48 : >3.2.2. Host (rfc3986)</a>
49 :
50 : @see
51 : @ref make_ipv4_address,
52 : @ref ipv6_address.
53 : */
54 : class BOOST_COROSIO_DECL ipv4_address
55 : {
56 : std::uint32_t addr_ = 0;
57 :
58 : public:
59 : /** The number of characters in the longest possible IPv4 string.
60 :
61 : The longest IPv4 address string is "255.255.255.255".
62 : */
63 : static constexpr std::size_t max_str_len = 15;
64 :
65 : /** The type used to represent an address as an unsigned integer.
66 : */
67 : using uint_type = std::uint32_t;
68 :
69 : /** The type used to represent an address as an array of bytes.
70 : */
71 : using bytes_type = std::array<unsigned char, 4>;
72 :
73 : /** Default constructor.
74 :
75 : Constructs the unspecified address (0.0.0.0).
76 : */
77 HIT 140872 : ipv4_address() = default;
78 :
79 : /** Copy constructor.
80 : */
81 : ipv4_address(ipv4_address const&) = default;
82 :
83 : /** Copy assignment.
84 :
85 : @return A reference to this object.
86 : */
87 : ipv4_address& operator=(ipv4_address const&) = default;
88 :
89 : /** Construct from an unsigned integer.
90 :
91 : This function constructs an address from
92 : the unsigned integer `u`, where the most
93 : significant byte forms the first octet
94 : of the resulting address.
95 :
96 : @param u The integer to construct from.
97 : */
98 : explicit ipv4_address(uint_type u) noexcept;
99 :
100 : /** Construct from an array of bytes.
101 :
102 : This function constructs an address
103 : from the array in `bytes`, which is
104 : interpreted in big-endian.
105 :
106 : @param bytes The value to construct from.
107 : */
108 : explicit ipv4_address(bytes_type const& bytes) noexcept;
109 :
110 : /** Construct from a string.
111 :
112 : This function constructs an address from
113 : the string `s`, which must contain a valid
114 : IPv4 address string or else an exception
115 : is thrown.
116 :
117 : @par Exception Safety
118 : Strong guarantee.
119 :
120 : @throws std::system_error `errc::invalid_argument` if the input
121 : failed to parse correctly.
122 :
123 : @note For a non-throwing parse function,
124 : use @ref make_ipv4_address.
125 :
126 : @param s The string to parse.
127 :
128 : @par Specification
129 : @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
130 : >3.2.2. Host (rfc3986)</a>
131 :
132 : @see
133 : @ref make_ipv4_address.
134 : */
135 : explicit ipv4_address(std::string_view s);
136 :
137 : /** Return the address as bytes, in network byte order.
138 :
139 : @return The address as an array of bytes.
140 : */
141 : bytes_type to_bytes() const noexcept;
142 :
143 : /** Return the address as an unsigned integer.
144 :
145 : @return The address as an unsigned integer.
146 : */
147 : uint_type to_uint() const noexcept;
148 :
149 : /** Return the address as a string in dotted decimal format.
150 :
151 : @par Example
152 : @par !example to_string
153 :
154 : @return The address as a string.
155 : */
156 : std::string to_string() const;
157 :
158 : /** Write a dotted decimal string representing the address to a buffer.
159 :
160 : The resulting buffer is not null-terminated.
161 :
162 : @throws std::length_error `dest_size < ipv4_address::max_str_len`
163 :
164 : @param dest The buffer in which to write,
165 : which must have at least `dest_size` space.
166 :
167 : @param dest_size The size of the output buffer.
168 :
169 : @return The formatted string view.
170 : */
171 : std::string_view to_buffer(char* dest, std::size_t dest_size) const;
172 :
173 : /** Return true if the address is a loopback address.
174 :
175 : @return `true` if the address is a loopback address.
176 : */
177 : bool is_loopback() const noexcept;
178 :
179 : /** Return true if the address is unspecified.
180 :
181 : @return `true` if the address is unspecified.
182 : */
183 : bool is_unspecified() const noexcept;
184 :
185 : /** Return true if the address is a multicast address.
186 :
187 : @return `true` if the address is a multicast address.
188 : */
189 : bool is_multicast() const noexcept;
190 :
191 : /** Return true if two addresses are equal.
192 :
193 : @return `true` if the addresses are equal, otherwise `false`.
194 : */
195 : friend bool
196 157 : operator==(ipv4_address const& a1, ipv4_address const& a2) noexcept
197 : {
198 157 : return a1.addr_ == a2.addr_;
199 : }
200 :
201 : /** Order two addresses.
202 :
203 : Establishes a strict total ordering consistent with
204 : `operator==`: addresses are ordered by their integer
205 : value, most significant octet first. This makes
206 : `ipv4_address` usable as a key in ordered containers
207 : such as `std::map` and `std::set`.
208 :
209 : @return The relative order of `a1` and `a2`.
210 : */
211 : friend std::strong_ordering
212 23 : operator<=>(ipv4_address const& a1, ipv4_address const& a2) noexcept
213 : {
214 23 : return a1.addr_ <=> a2.addr_;
215 : }
216 :
217 : /** Return an address object that represents any address.
218 :
219 : @return The any address (0.0.0.0).
220 : */
221 28 : static ipv4_address any() noexcept
222 : {
223 28 : return ipv4_address();
224 : }
225 :
226 : /** Return an address object that represents the loopback address.
227 :
228 : @return The loopback address (127.0.0.1).
229 : */
230 5147 : static ipv4_address loopback() noexcept
231 : {
232 5147 : return ipv4_address(0x7F000001);
233 : }
234 :
235 : /** Return an address object that represents the broadcast address.
236 :
237 : @return The broadcast address (255.255.255.255).
238 : */
239 6 : static ipv4_address broadcast() noexcept
240 : {
241 6 : return ipv4_address(0xFFFFFFFF);
242 : }
243 :
244 : /** Format the address to an output stream.
245 :
246 : IPv4 addresses written to output streams
247 : are written in their dotted decimal format.
248 :
249 : @param os The output stream.
250 : @param addr The address to format.
251 : @return The output stream.
252 : */
253 : friend BOOST_COROSIO_DECL std::ostream&
254 : operator<<(std::ostream& os, ipv4_address const& addr);
255 :
256 : private:
257 : friend class ipv6_address;
258 :
259 : std::size_t print_impl(char* dest) const noexcept;
260 : };
261 :
262 : /** Create an IPv4 address from an IP address string in dotted decimal form.
263 :
264 : @param s The string to parse.
265 : @return The error code, empty on success, and the parsed
266 : address — default-constructed on failure.
267 : */
268 : [[nodiscard]] BOOST_COROSIO_DECL capy::io_result<ipv4_address>
269 : make_ipv4_address(std::string_view s) noexcept;
270 :
271 : } // namespace boost::corosio
272 :
273 : namespace std {
274 :
275 : /// Hash support for `boost::corosio::ipv4_address`.
276 : template<>
277 : struct hash<boost::corosio::ipv4_address>
278 : {
279 : /// Return the hash of `addr`.
280 : std::size_t
281 20 : operator()(boost::corosio::ipv4_address const& addr) const noexcept
282 : {
283 20 : return hash<std::uint32_t>()(addr.to_uint());
284 : }
285 : };
286 :
287 : } // namespace std
288 :
289 : #endif
|