1  
//
1  
//
2  
// Copyright (c) 2026 Vinnie Falco (vinnie dot falco at gmail dot com)
2  
// Copyright (c) 2026 Vinnie Falco (vinnie dot falco at gmail dot com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/corosio
7  
// Official repository: https://github.com/cppalliance/corosio
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_COROSIO_IPV4_ADDRESS_HPP
10  
#ifndef BOOST_COROSIO_IPV4_ADDRESS_HPP
11  
#define BOOST_COROSIO_IPV4_ADDRESS_HPP
11  
#define BOOST_COROSIO_IPV4_ADDRESS_HPP
12  

12  

13  
#include <boost/corosio/detail/config.hpp>
13  
#include <boost/corosio/detail/config.hpp>
14  

14  

15  
#include <array>
15  
#include <array>
16  
#include <cstdint>
16  
#include <cstdint>
17  
#include <iosfwd>
17  
#include <iosfwd>
18  
#include <string>
18  
#include <string>
19  
#include <string_view>
19  
#include <string_view>
20  
#include <system_error>
20  
#include <system_error>
21  

21  

22  
namespace boost::corosio {
22  
namespace boost::corosio {
23  

23  

24  
/** An IP version 4 style address.
24  
/** An IP version 4 style address.
25  

25  

26  
    Objects of this type are used to construct,
26  
    Objects of this type are used to construct,
27  
    parse, and manipulate IP version 4 addresses.
27  
    parse, and manipulate IP version 4 addresses.
28  

28  

29  
    @par BNF
29  
    @par BNF
30  
    @code
30  
    @code
31  
    IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
31  
    IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
32  

32  

33  
    dec-octet   = DIGIT                 ; 0-9
33  
    dec-octet   = DIGIT                 ; 0-9
34  
                / %x31-39 DIGIT         ; 10-99
34  
                / %x31-39 DIGIT         ; 10-99
35  
                / "1" 2DIGIT            ; 100-199
35  
                / "1" 2DIGIT            ; 100-199
36  
                / "2" %x30-34 DIGIT     ; 200-249
36  
                / "2" %x30-34 DIGIT     ; 200-249
37  
                / "25" %x30-35          ; 250-255
37  
                / "25" %x30-35          ; 250-255
38  
    @endcode
38  
    @endcode
39  

39  

40  
    @par Specification
40  
    @par Specification
41  
    @li <a href="https://en.wikipedia.org/wiki/IPv4">IPv4 (Wikipedia)</a>
41  
    @li <a href="https://en.wikipedia.org/wiki/IPv4">IPv4 (Wikipedia)</a>
42  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
42  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
43  
        >3.2.2. Host (rfc3986)</a>
43  
        >3.2.2. Host (rfc3986)</a>
44  

44  

45  
    @see
45  
    @see
46  
        @ref parse_ipv4_address,
46  
        @ref parse_ipv4_address,
47  
        @ref ipv6_address.
47  
        @ref ipv6_address.
48  
*/
48  
*/
49  
class BOOST_COROSIO_DECL ipv4_address
49  
class BOOST_COROSIO_DECL ipv4_address
50  
{
50  
{
51  
    std::uint32_t addr_ = 0;
51  
    std::uint32_t addr_ = 0;
52  

52  

53  
public:
53  
public:
54  
    /** The number of characters in the longest possible IPv4 string.
54  
    /** The number of characters in the longest possible IPv4 string.
55  

55  

56  
        The longest IPv4 address string is "255.255.255.255".
56  
        The longest IPv4 address string is "255.255.255.255".
57  
    */
57  
    */
58  
    static constexpr std::size_t max_str_len = 15;
58  
    static constexpr std::size_t max_str_len = 15;
59  

59  

60  
    /** The type used to represent an address as an unsigned integer.
60  
    /** The type used to represent an address as an unsigned integer.
61  
    */
61  
    */
62  
    using uint_type = std::uint32_t;
62  
    using uint_type = std::uint32_t;
63  

63  

64  
    /** The type used to represent an address as an array of bytes.
64  
    /** The type used to represent an address as an array of bytes.
65  
    */
65  
    */
66  
    using bytes_type = std::array<unsigned char, 4>;
66  
    using bytes_type = std::array<unsigned char, 4>;
67  

67  

68  
    /** Default constructor.
68  
    /** Default constructor.
69  

69  

70  
        Constructs the unspecified address (0.0.0.0).
70  
        Constructs the unspecified address (0.0.0.0).
71  
    */
71  
    */
72  
    ipv4_address() = default;
72  
    ipv4_address() = default;
73  

73  

74  
    /** Copy constructor.
74  
    /** Copy constructor.
75  
    */
75  
    */
76  
    ipv4_address(ipv4_address const&) = default;
76  
    ipv4_address(ipv4_address const&) = default;
77  

77  

78  
    /** Copy assignment.
78  
    /** Copy assignment.
79  

79  

80  
        @return A reference to this object.
80  
        @return A reference to this object.
81  
    */
81  
    */
82  
    ipv4_address& operator=(ipv4_address const&) = default;
82  
    ipv4_address& operator=(ipv4_address const&) = default;
83  

83  

84  
    /** Construct from an unsigned integer.
84  
    /** Construct from an unsigned integer.
85  

85  

86  
        This function constructs an address from
86  
        This function constructs an address from
87  
        the unsigned integer `u`, where the most
87  
        the unsigned integer `u`, where the most
88  
        significant byte forms the first octet
88  
        significant byte forms the first octet
89  
        of the resulting address.
89  
        of the resulting address.
90  

90  

91  
        @param u The integer to construct from.
91  
        @param u The integer to construct from.
92  
    */
92  
    */
93  
    explicit
93  
    explicit
94  
    ipv4_address(uint_type u) noexcept;
94  
    ipv4_address(uint_type u) noexcept;
95  

95  

96  
    /** Construct from an array of bytes.
96  
    /** Construct from an array of bytes.
97  

97  

98  
        This function constructs an address
98  
        This function constructs an address
99  
        from the array in `bytes`, which is
99  
        from the array in `bytes`, which is
100  
        interpreted in big-endian.
100  
        interpreted in big-endian.
101  

101  

102  
        @param bytes The value to construct from.
102  
        @param bytes The value to construct from.
103  
    */
103  
    */
104  
    explicit
104  
    explicit
105  
    ipv4_address(bytes_type const& bytes) noexcept;
105  
    ipv4_address(bytes_type const& bytes) noexcept;
106  

106  

107  
    /** Construct from a string.
107  
    /** Construct from a string.
108  

108  

109  
        This function constructs an address from
109  
        This function constructs an address from
110  
        the string `s`, which must contain a valid
110  
        the string `s`, which must contain a valid
111  
        IPv4 address string or else an exception
111  
        IPv4 address string or else an exception
112  
        is thrown.
112  
        is thrown.
113  

113  

114  
        @note For a non-throwing parse function,
114  
        @note For a non-throwing parse function,
115  
        use @ref parse_ipv4_address.
115  
        use @ref parse_ipv4_address.
116  

116  

117  
        @par Exception Safety
117  
        @par Exception Safety
118  
        Exceptions thrown on invalid input.
118  
        Exceptions thrown on invalid input.
119  

119  

120  
        @throw std::invalid_argument The input failed to parse correctly.
120  
        @throw std::invalid_argument The input failed to parse correctly.
121  

121  

122  
        @param s The string to parse.
122  
        @param s The string to parse.
123  

123  

124  
        @par Specification
124  
        @par Specification
125  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
125  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
126  
            >3.2.2. Host (rfc3986)</a>
126  
            >3.2.2. Host (rfc3986)</a>
127  

127  

128  
        @see
128  
        @see
129  
            @ref parse_ipv4_address.
129  
            @ref parse_ipv4_address.
130  
    */
130  
    */
131  
    explicit
131  
    explicit
132  
    ipv4_address(std::string_view s);
132  
    ipv4_address(std::string_view s);
133  

133  

134  
    /** Return the address as bytes, in network byte order.
134  
    /** Return the address as bytes, in network byte order.
135  

135  

136  
        @return The address as an array of bytes.
136  
        @return The address as an array of bytes.
137  
    */
137  
    */
138  
    bytes_type
138  
    bytes_type
139  
    to_bytes() const noexcept;
139  
    to_bytes() const noexcept;
140  

140  

141  
    /** Return the address as an unsigned integer.
141  
    /** Return the address as an unsigned integer.
142  

142  

143  
        @return The address as an unsigned integer.
143  
        @return The address as an unsigned integer.
144  
    */
144  
    */
145  
    uint_type
145  
    uint_type
146  
    to_uint() const noexcept;
146  
    to_uint() const noexcept;
147  

147  

148  
    /** Return the address as a string in dotted decimal format.
148  
    /** Return the address as a string in dotted decimal format.
149  

149  

150  
        @par Example
150  
        @par Example
151  
        @code
151  
        @code
152  
        assert( ipv4_address(0x01020304).to_string() == "1.2.3.4" );
152  
        assert( ipv4_address(0x01020304).to_string() == "1.2.3.4" );
153  
        @endcode
153  
        @endcode
154  

154  

155  
        @return The address as a string.
155  
        @return The address as a string.
156  
    */
156  
    */
157  
    std::string
157  
    std::string
158  
    to_string() const;
158  
    to_string() const;
159  

159  

160  
    /** Write a dotted decimal string representing the address to a buffer.
160  
    /** Write a dotted decimal string representing the address to a buffer.
161  

161  

162  
        The resulting buffer is not null-terminated.
162  
        The resulting buffer is not null-terminated.
163  

163  

164  
        @throw std::length_error `dest_size < ipv4_address::max_str_len`
164  
        @throw std::length_error `dest_size < ipv4_address::max_str_len`
165  

165  

166  
        @return The formatted string view.
166  
        @return The formatted string view.
167  

167  

168  
        @param dest The buffer in which to write,
168  
        @param dest The buffer in which to write,
169  
        which must have at least `dest_size` space.
169  
        which must have at least `dest_size` space.
170  

170  

171  
        @param dest_size The size of the output buffer.
171  
        @param dest_size The size of the output buffer.
172  
    */
172  
    */
173  
    std::string_view
173  
    std::string_view
174  
    to_buffer(char* dest, std::size_t dest_size) const;
174  
    to_buffer(char* dest, std::size_t dest_size) const;
175  

175  

176  
    /** Return true if the address is a loopback address.
176  
    /** Return true if the address is a loopback address.
177  

177  

178  
        @return `true` if the address is a loopback address.
178  
        @return `true` if the address is a loopback address.
179  
    */
179  
    */
180  
    bool
180  
    bool
181  
    is_loopback() const noexcept;
181  
    is_loopback() const noexcept;
182  

182  

183  
    /** Return true if the address is unspecified.
183  
    /** Return true if the address is unspecified.
184  

184  

185  
        @return `true` if the address is unspecified.
185  
        @return `true` if the address is unspecified.
186  
    */
186  
    */
187  
    bool
187  
    bool
188  
    is_unspecified() const noexcept;
188  
    is_unspecified() const noexcept;
189  

189  

190  
    /** Return true if the address is a multicast address.
190  
    /** Return true if the address is a multicast address.
191  

191  

192  
        @return `true` if the address is a multicast address.
192  
        @return `true` if the address is a multicast address.
193  
    */
193  
    */
194  
    bool
194  
    bool
195  
    is_multicast() const noexcept;
195  
    is_multicast() const noexcept;
196  

196  

197  
    /** Return true if two addresses are equal.
197  
    /** Return true if two addresses are equal.
198  

198  

199  
        @return `true` if the addresses are equal, otherwise `false`.
199  
        @return `true` if the addresses are equal, otherwise `false`.
200  
    */
200  
    */
201  
    friend
201  
    friend
202  
    bool
202  
    bool
203  
    operator==(ipv4_address const& a1, ipv4_address const& a2) noexcept
203  
    operator==(ipv4_address const& a1, ipv4_address const& a2) noexcept
204  
    {
204  
    {
205  
        return a1.addr_ == a2.addr_;
205  
        return a1.addr_ == a2.addr_;
206  
    }
206  
    }
207  

207  

208  
    /** Return true if two addresses are not equal.
208  
    /** Return true if two addresses are not equal.
209  

209  

210  
        @return `true` if the addresses are not equal, otherwise `false`.
210  
        @return `true` if the addresses are not equal, otherwise `false`.
211  
    */
211  
    */
212  
    friend
212  
    friend
213  
    bool
213  
    bool
214  
    operator!=(ipv4_address const& a1, ipv4_address const& a2) noexcept
214  
    operator!=(ipv4_address const& a1, ipv4_address const& a2) noexcept
215  
    {
215  
    {
216  
        return a1.addr_ != a2.addr_;
216  
        return a1.addr_ != a2.addr_;
217  
    }
217  
    }
218  

218  

219  
    /** Return an address object that represents any address.
219  
    /** Return an address object that represents any address.
220  

220  

221  
        @return The any address (0.0.0.0).
221  
        @return The any address (0.0.0.0).
222  
    */
222  
    */
223  
    static
223  
    static
224  
    ipv4_address
224  
    ipv4_address
225  
    any() noexcept
225  
    any() noexcept
226  
    {
226  
    {
227  
        return ipv4_address();
227  
        return ipv4_address();
228  
    }
228  
    }
229  

229  

230  
    /** Return an address object that represents the loopback address.
230  
    /** Return an address object that represents the loopback address.
231  

231  

232  
        @return The loopback address (127.0.0.1).
232  
        @return The loopback address (127.0.0.1).
233  
    */
233  
    */
234  
    static
234  
    static
235  
    ipv4_address
235  
    ipv4_address
236  
    loopback() noexcept
236  
    loopback() noexcept
237  
    {
237  
    {
238  
        return ipv4_address(0x7F000001);
238  
        return ipv4_address(0x7F000001);
239  
    }
239  
    }
240  

240  

241  
    /** Return an address object that represents the broadcast address.
241  
    /** Return an address object that represents the broadcast address.
242  

242  

243  
        @return The broadcast address (255.255.255.255).
243  
        @return The broadcast address (255.255.255.255).
244  
    */
244  
    */
245  
    static
245  
    static
246  
    ipv4_address
246  
    ipv4_address
247  
    broadcast() noexcept
247  
    broadcast() noexcept
248  
    {
248  
    {
249  
        return ipv4_address(0xFFFFFFFF);
249  
        return ipv4_address(0xFFFFFFFF);
250  
    }
250  
    }
251  

251  

252  
    /** Format the address to an output stream.
252  
    /** Format the address to an output stream.
253  

253  

254  
        IPv4 addresses written to output streams
254  
        IPv4 addresses written to output streams
255  
        are written in their dotted decimal format.
255  
        are written in their dotted decimal format.
256  

256  

257  
        @param os The output stream.
257  
        @param os The output stream.
258  
        @param addr The address to format.
258  
        @param addr The address to format.
259  
        @return The output stream.
259  
        @return The output stream.
260  
    */
260  
    */
261  
    friend
261  
    friend
262  
    BOOST_COROSIO_DECL
262  
    BOOST_COROSIO_DECL
263  
    std::ostream&
263  
    std::ostream&
264  
    operator<<(std::ostream& os, ipv4_address const& addr);
264  
    operator<<(std::ostream& os, ipv4_address const& addr);
265  

265  

266  
private:
266  
private:
267  
    friend class ipv6_address;
267  
    friend class ipv6_address;
268  

268  

269  
    std::size_t
269  
    std::size_t
270  
    print_impl(char* dest) const noexcept;
270  
    print_impl(char* dest) const noexcept;
271  
};
271  
};
272  

272  

273  
//------------------------------------------------
273  
//------------------------------------------------
274  

274  

275  
/** Return an IPv4 address from an IP address string in dotted decimal form.
275  
/** Return an IPv4 address from an IP address string in dotted decimal form.
276  

276  

277  
    @param s The string to parse.
277  
    @param s The string to parse.
278  
    @param addr The address to store the result.
278  
    @param addr The address to store the result.
279  
    @return An error code (empty on success).
279  
    @return An error code (empty on success).
280  
*/
280  
*/
281  
[[nodiscard]] BOOST_COROSIO_DECL
281  
[[nodiscard]] BOOST_COROSIO_DECL
282  
std::error_code
282  
std::error_code
283  
parse_ipv4_address(
283  
parse_ipv4_address(
284  
    std::string_view s,
284  
    std::string_view s,
285  
    ipv4_address& addr) noexcept;
285  
    ipv4_address& addr) noexcept;
286  

286  

287  
} // namespace boost::corosio
287  
} // namespace boost::corosio
288  

288  

289  
#endif
289  
#endif