1  
//
1  
//
2  
// Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.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 ipv4_address(uint_type u) noexcept;
93  
    explicit ipv4_address(uint_type u) noexcept;
94  

94  

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

96  

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

100  

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

104  

105  
    /** Construct from a string.
105  
    /** Construct from a string.
106  

106  

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

111  

112  
        @note For a non-throwing parse function,
112  
        @note For a non-throwing parse function,
113  
        use @ref parse_ipv4_address.
113  
        use @ref parse_ipv4_address.
114  

114  

115  
        @par Exception Safety
115  
        @par Exception Safety
116  
        Exceptions thrown on invalid input.
116  
        Exceptions thrown on invalid input.
117  

117  

118  
        @throw std::invalid_argument The input failed to parse correctly.
118  
        @throw std::invalid_argument The input failed to parse correctly.
119  

119  

120  
        @param s The string to parse.
120  
        @param s The string to parse.
121  

121  

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

125  

126  
        @see
126  
        @see
127  
            @ref parse_ipv4_address.
127  
            @ref parse_ipv4_address.
128  
    */
128  
    */
129  
    explicit ipv4_address(std::string_view s);
129  
    explicit ipv4_address(std::string_view s);
130  

130  

131  
    /** Return the address as bytes, in network byte order.
131  
    /** Return the address as bytes, in network byte order.
132  

132  

133  
        @return The address as an array of bytes.
133  
        @return The address as an array of bytes.
134  
    */
134  
    */
135  
    bytes_type to_bytes() const noexcept;
135  
    bytes_type to_bytes() const noexcept;
136  

136  

137  
    /** Return the address as an unsigned integer.
137  
    /** Return the address as an unsigned integer.
138  

138  

139  
        @return The address as an unsigned integer.
139  
        @return The address as an unsigned integer.
140  
    */
140  
    */
141  
    uint_type to_uint() const noexcept;
141  
    uint_type to_uint() const noexcept;
142  

142  

143  
    /** Return the address as a string in dotted decimal format.
143  
    /** Return the address as a string in dotted decimal format.
144  

144  

145  
        @par Example
145  
        @par Example
146  
        @code
146  
        @code
147  
        assert( ipv4_address(0x01020304).to_string() == "1.2.3.4" );
147  
        assert( ipv4_address(0x01020304).to_string() == "1.2.3.4" );
148  
        @endcode
148  
        @endcode
149  

149  

150  
        @return The address as a string.
150  
        @return The address as a string.
151  
    */
151  
    */
152  
    std::string to_string() const;
152  
    std::string to_string() const;
153  

153  

154  
    /** Write a dotted decimal string representing the address to a buffer.
154  
    /** Write a dotted decimal string representing the address to a buffer.
155  

155  

156  
        The resulting buffer is not null-terminated.
156  
        The resulting buffer is not null-terminated.
157  

157  

158  
        @throw std::length_error `dest_size < ipv4_address::max_str_len`
158  
        @throw std::length_error `dest_size < ipv4_address::max_str_len`
159  

159  

160  
        @return The formatted string view.
160  
        @return The formatted string view.
161  

161  

162  
        @param dest The buffer in which to write,
162  
        @param dest The buffer in which to write,
163  
        which must have at least `dest_size` space.
163  
        which must have at least `dest_size` space.
164  

164  

165  
        @param dest_size The size of the output buffer.
165  
        @param dest_size The size of the output buffer.
166  
    */
166  
    */
167  
    std::string_view to_buffer(char* dest, std::size_t dest_size) const;
167  
    std::string_view to_buffer(char* dest, std::size_t dest_size) const;
168  

168  

169  
    /** Return true if the address is a loopback address.
169  
    /** Return true if the address is a loopback address.
170  

170  

171  
        @return `true` if the address is a loopback address.
171  
        @return `true` if the address is a loopback address.
172  
    */
172  
    */
173  
    bool is_loopback() const noexcept;
173  
    bool is_loopback() const noexcept;
174  

174  

175  
    /** Return true if the address is unspecified.
175  
    /** Return true if the address is unspecified.
176  

176  

177  
        @return `true` if the address is unspecified.
177  
        @return `true` if the address is unspecified.
178  
    */
178  
    */
179  
    bool is_unspecified() const noexcept;
179  
    bool is_unspecified() const noexcept;
180  

180  

181  
    /** Return true if the address is a multicast address.
181  
    /** Return true if the address is a multicast address.
182  

182  

183  
        @return `true` if the address is a multicast address.
183  
        @return `true` if the address is a multicast address.
184  
    */
184  
    */
185  
    bool is_multicast() const noexcept;
185  
    bool is_multicast() const noexcept;
186  

186  

187  
    /** Return true if two addresses are equal.
187  
    /** Return true if two addresses are equal.
188  

188  

189  
        @return `true` if the addresses are equal, otherwise `false`.
189  
        @return `true` if the addresses are equal, otherwise `false`.
190  
    */
190  
    */
191  
    friend bool
191  
    friend bool
192  
    operator==(ipv4_address const& a1, ipv4_address const& a2) noexcept
192  
    operator==(ipv4_address const& a1, ipv4_address const& a2) noexcept
193  
    {
193  
    {
194  
        return a1.addr_ == a2.addr_;
194  
        return a1.addr_ == a2.addr_;
195  
    }
195  
    }
196  

196  

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

198  

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

206  

207  
    /** Return an address object that represents any address.
207  
    /** Return an address object that represents any address.
208  

208  

209  
        @return The any address (0.0.0.0).
209  
        @return The any address (0.0.0.0).
210  
    */
210  
    */
211  
    static ipv4_address any() noexcept
211  
    static ipv4_address any() noexcept
212  
    {
212  
    {
213  
        return ipv4_address();
213  
        return ipv4_address();
214  
    }
214  
    }
215  

215  

216  
    /** Return an address object that represents the loopback address.
216  
    /** Return an address object that represents the loopback address.
217  

217  

218  
        @return The loopback address (127.0.0.1).
218  
        @return The loopback address (127.0.0.1).
219  
    */
219  
    */
220  
    static ipv4_address loopback() noexcept
220  
    static ipv4_address loopback() noexcept
221  
    {
221  
    {
222  
        return ipv4_address(0x7F000001);
222  
        return ipv4_address(0x7F000001);
223  
    }
223  
    }
224  

224  

225  
    /** Return an address object that represents the broadcast address.
225  
    /** Return an address object that represents the broadcast address.
226  

226  

227  
        @return The broadcast address (255.255.255.255).
227  
        @return The broadcast address (255.255.255.255).
228  
    */
228  
    */
229  
    static ipv4_address broadcast() noexcept
229  
    static ipv4_address broadcast() noexcept
230  
    {
230  
    {
231  
        return ipv4_address(0xFFFFFFFF);
231  
        return ipv4_address(0xFFFFFFFF);
232  
    }
232  
    }
233  

233  

234  
    /** Format the address to an output stream.
234  
    /** Format the address to an output stream.
235  

235  

236  
        IPv4 addresses written to output streams
236  
        IPv4 addresses written to output streams
237  
        are written in their dotted decimal format.
237  
        are written in their dotted decimal format.
238  

238  

239  
        @param os The output stream.
239  
        @param os The output stream.
240  
        @param addr The address to format.
240  
        @param addr The address to format.
241  
        @return The output stream.
241  
        @return The output stream.
242  
    */
242  
    */
243  
    friend BOOST_COROSIO_DECL std::ostream&
243  
    friend BOOST_COROSIO_DECL std::ostream&
244  
    operator<<(std::ostream& os, ipv4_address const& addr);
244  
    operator<<(std::ostream& os, ipv4_address const& addr);
245  

245  

246  
private:
246  
private:
247  
    friend class ipv6_address;
247  
    friend class ipv6_address;
248  

248  

249  
    std::size_t print_impl(char* dest) const noexcept;
249  
    std::size_t print_impl(char* dest) const noexcept;
250  
};
250  
};
251  

251  

252  
/** Return an IPv4 address from an IP address string in dotted decimal form.
252  
/** Return an IPv4 address from an IP address string in dotted decimal form.
253  

253  

254  
    @param s The string to parse.
254  
    @param s The string to parse.
255  
    @param addr The address to store the result.
255  
    @param addr The address to store the result.
256  
    @return An error code (empty on success).
256  
    @return An error code (empty on success).
257  
*/
257  
*/
258  
[[nodiscard]] BOOST_COROSIO_DECL std::error_code
258  
[[nodiscard]] BOOST_COROSIO_DECL std::error_code
259  
parse_ipv4_address(std::string_view s, ipv4_address& addr) noexcept;
259  
parse_ipv4_address(std::string_view s, ipv4_address& addr) noexcept;
260  

260  

261  
} // namespace boost::corosio
261  
} // namespace boost::corosio
262  

262  

263  
#endif
263  
#endif