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_IPV6_ADDRESS_HPP
10  
#ifndef BOOST_COROSIO_IPV6_ADDRESS_HPP
11  
#define BOOST_COROSIO_IPV6_ADDRESS_HPP
11  
#define BOOST_COROSIO_IPV6_ADDRESS_HPP
12  

12  

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

14  

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

20  

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

22  

24  
class ipv4_address;
23  
class ipv4_address;
25  

24  

26  
/** An IP version 6 style address.
25  
/** An IP version 6 style address.
27  

26  

28  
    Objects of this type are used to construct,
27  
    Objects of this type are used to construct,
29  
    parse, and manipulate IP version 6 addresses.
28  
    parse, and manipulate IP version 6 addresses.
30  

29  

31  
    @par BNF
30  
    @par BNF
32  
    @code
31  
    @code
33  
    IPv6address =                            6( h16 ":" ) ls32
32  
    IPv6address =                            6( h16 ":" ) ls32
34  
                /                       "::" 5( h16 ":" ) ls32
33  
                /                       "::" 5( h16 ":" ) ls32
35  
                / [               h16 ] "::" 4( h16 ":" ) ls32
34  
                / [               h16 ] "::" 4( h16 ":" ) ls32
36  
                / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
35  
                / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
37  
                / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
36  
                / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
38  
                / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
37  
                / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
39  
                / [ *4( h16 ":" ) h16 ] "::"              ls32
38  
                / [ *4( h16 ":" ) h16 ] "::"              ls32
40  
                / [ *5( h16 ":" ) h16 ] "::"              h16
39  
                / [ *5( h16 ":" ) h16 ] "::"              h16
41  
                / [ *6( h16 ":" ) h16 ] "::"
40  
                / [ *6( h16 ":" ) h16 ] "::"
42  

41  

43  
    ls32        = ( h16 ":" h16 ) / IPv4address
42  
    ls32        = ( h16 ":" h16 ) / IPv4address
44  
                ; least-significant 32 bits of address
43  
                ; least-significant 32 bits of address
45  

44  

46  
    h16         = 1*4HEXDIG
45  
    h16         = 1*4HEXDIG
47  
                ; 16 bits of address represented in hexadecimal
46  
                ; 16 bits of address represented in hexadecimal
48  
    @endcode
47  
    @endcode
49  

48  

50  
    @par Specification
49  
    @par Specification
51  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc4291"
50  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc4291"
52  
        >IP Version 6 Addressing Architecture (rfc4291)</a>
51  
        >IP Version 6 Addressing Architecture (rfc4291)</a>
53  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
52  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
54  
        >3.2.2. Host (rfc3986)</a>
53  
        >3.2.2. Host (rfc3986)</a>
55  

54  

56  
    @see
55  
    @see
57  
        @ref ipv4_address,
56  
        @ref ipv4_address,
58  
        @ref parse_ipv6_address.
57  
        @ref parse_ipv6_address.
59  
*/
58  
*/
60  
class BOOST_COROSIO_DECL ipv6_address
59  
class BOOST_COROSIO_DECL ipv6_address
61  
{
60  
{
62  
    std::array<unsigned char, 16> addr_{};
61  
    std::array<unsigned char, 16> addr_{};
63  

62  

64  
public:
63  
public:
65  
    /** The number of characters in the longest possible IPv6 string.
64  
    /** The number of characters in the longest possible IPv6 string.
66  

65  

67  
        The longest IPv6 address is:
66  
        The longest IPv6 address is:
68  
        @code
67  
        @code
69  
        ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
68  
        ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
70  
        @endcode
69  
        @endcode
71  
        or with IPv4-mapped:
70  
        or with IPv4-mapped:
72  
        @code
71  
        @code
73  
        ::ffff:255.255.255.255
72  
        ::ffff:255.255.255.255
74  
        @endcode
73  
        @endcode
75  
    */
74  
    */
76  
    static constexpr std::size_t max_str_len = 49;
75  
    static constexpr std::size_t max_str_len = 49;
77  

76  

78  
    /** The type used to represent an address as an array of bytes.
77  
    /** The type used to represent an address as an array of bytes.
79  

78  

80  
        Octets are stored in network byte order.
79  
        Octets are stored in network byte order.
81  
    */
80  
    */
82  
    using bytes_type = std::array<unsigned char, 16>;
81  
    using bytes_type = std::array<unsigned char, 16>;
83  

82  

84  
    /** Default constructor.
83  
    /** Default constructor.
85  

84  

86  
        Constructs the unspecified address (::).
85  
        Constructs the unspecified address (::).
87  

86  

88  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2"
87  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2"
89  
            >2.5.2. The Unspecified Address</a>
88  
            >2.5.2. The Unspecified Address</a>
90  

89  

91  
        @see
90  
        @see
92  
            @ref is_unspecified
91  
            @ref is_unspecified
93  
    */
92  
    */
94  
    ipv6_address() = default;
93  
    ipv6_address() = default;
95  

94  

96  
    /** Copy constructor.
95  
    /** Copy constructor.
97  
    */
96  
    */
98  
    ipv6_address(ipv6_address const&) = default;
97  
    ipv6_address(ipv6_address const&) = default;
99  

98  

100  
    /** Copy assignment.
99  
    /** Copy assignment.
101  

100  

102  
        @return A reference to this object.
101  
        @return A reference to this object.
103  
    */
102  
    */
104  
    ipv6_address& operator=(ipv6_address const&) = default;
103  
    ipv6_address& operator=(ipv6_address const&) = default;
105  

104  

106  
    /** Construct from an array of bytes.
105  
    /** Construct from an array of bytes.
107  

106  

108  
        This function constructs an address
107  
        This function constructs an address
109  
        from the array in `bytes`, which is
108  
        from the array in `bytes`, which is
110  
        interpreted in big-endian.
109  
        interpreted in big-endian.
111  

110  

112  
        @param bytes The value to construct from.
111  
        @param bytes The value to construct from.
113  
    */
112  
    */
114  
    explicit ipv6_address(bytes_type const& bytes) noexcept;
113  
    explicit ipv6_address(bytes_type const& bytes) noexcept;
115  

114  

116  
    /** Construct from an IPv4 address.
115  
    /** Construct from an IPv4 address.
117  

116  

118  
        This function constructs an IPv6 address
117  
        This function constructs an IPv6 address
119  
        from the IPv4 address `addr`. The resulting
118  
        from the IPv4 address `addr`. The resulting
120  
        address is an IPv4-Mapped IPv6 Address.
119  
        address is an IPv4-Mapped IPv6 Address.
121  

120  

122  
        @param addr The address to construct from.
121  
        @param addr The address to construct from.
123  

122  

124  
        @par Specification
123  
        @par Specification
125  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2"
124  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2"
126  
            >2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
125  
            >2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
127  
    */
126  
    */
128  
    explicit ipv6_address(ipv4_address const& addr) noexcept;
127  
    explicit ipv6_address(ipv4_address const& addr) noexcept;
129  

128  

130  
    /** Construct from a string.
129  
    /** Construct from a string.
131  

130  

132  
        This function constructs an address from
131  
        This function constructs an address from
133  
        the string `s`, which must contain a valid
132  
        the string `s`, which must contain a valid
134  
        IPv6 address string or else an exception
133  
        IPv6 address string or else an exception
135  
        is thrown.
134  
        is thrown.
136  

135  

137  
        @note For a non-throwing parse function,
136  
        @note For a non-throwing parse function,
138  
        use @ref parse_ipv6_address.
137  
        use @ref parse_ipv6_address.
139  

138  

140  
        @par Exception Safety
139  
        @par Exception Safety
141  
        Exceptions thrown on invalid input.
140  
        Exceptions thrown on invalid input.
142  

141  

143  
        @throw std::invalid_argument
142  
        @throw std::invalid_argument
144  
        The input failed to parse correctly.
143  
        The input failed to parse correctly.
145  

144  

146  
        @param s The string to parse.
145  
        @param s The string to parse.
147  

146  

148  
        @par Specification
147  
        @par Specification
149  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
148  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
150  
            >3.2.2. Host (rfc3986)</a>
149  
            >3.2.2. Host (rfc3986)</a>
151  

150  

152  
        @see
151  
        @see
153  
            @ref parse_ipv6_address.
152  
            @ref parse_ipv6_address.
154  
    */
153  
    */
155  
    explicit ipv6_address(std::string_view s);
154  
    explicit ipv6_address(std::string_view s);
156  

155  

157  
    /** Return the address as bytes, in network byte order.
156  
    /** Return the address as bytes, in network byte order.
158  

157  

159  
        @return The address as an array of bytes.
158  
        @return The address as an array of bytes.
160  
    */
159  
    */
161  
    bytes_type to_bytes() const noexcept
160  
    bytes_type to_bytes() const noexcept
162  
    {
161  
    {
163  
        return addr_;
162  
        return addr_;
164  
    }
163  
    }
165  

164  

166  
    /** Return the address as a string.
165  
    /** Return the address as a string.
167  

166  

168  
        The returned string does not
167  
        The returned string does not
169  
        contain surrounding square brackets.
168  
        contain surrounding square brackets.
170  

169  

171  
        @par Example
170  
        @par Example
172  
        @code
171  
        @code
173  
        ipv6_address::bytes_type b = {{
172  
        ipv6_address::bytes_type b = {{
174  
                0, 1, 0, 2, 0, 3, 0, 4,
173  
                0, 1, 0, 2, 0, 3, 0, 4,
175  
                0, 5, 0, 6, 0, 7, 0, 8 }};
174  
                0, 5, 0, 6, 0, 7, 0, 8 }};
176  
        ipv6_address a(b);
175  
        ipv6_address a(b);
177  
        assert(a.to_string() == "1:2:3:4:5:6:7:8");
176  
        assert(a.to_string() == "1:2:3:4:5:6:7:8");
178  
        @endcode
177  
        @endcode
179  

178  

180  
        @return The address as a string.
179  
        @return The address as a string.
181  

180  

182  
        @par Specification
181  
        @par Specification
183  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2">
182  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2">
184  
            2.2. Text Representation of Addresses (rfc4291)</a>
183  
            2.2. Text Representation of Addresses (rfc4291)</a>
185  
    */
184  
    */
186  
    std::string to_string() const;
185  
    std::string to_string() const;
187  

186  

188  
    /** Write a string representing the address to a buffer.
187  
    /** Write a string representing the address to a buffer.
189  

188  

190  
        The resulting buffer is not null-terminated.
189  
        The resulting buffer is not null-terminated.
191  

190  

192  
        @throw std::length_error `dest_size < ipv6_address::max_str_len`
191  
        @throw std::length_error `dest_size < ipv6_address::max_str_len`
193  

192  

194  
        @return The formatted string view.
193  
        @return The formatted string view.
195  

194  

196  
        @param dest The buffer in which to write,
195  
        @param dest The buffer in which to write,
197  
        which must have at least `dest_size` space.
196  
        which must have at least `dest_size` space.
198  

197  

199  
        @param dest_size The size of the output buffer.
198  
        @param dest_size The size of the output buffer.
200  
    */
199  
    */
201  
    std::string_view to_buffer(char* dest, std::size_t dest_size) const;
200  
    std::string_view to_buffer(char* dest, std::size_t dest_size) const;
202  

201  

203  
    /** Return true if the address is unspecified.
202  
    /** Return true if the address is unspecified.
204  

203  

205  
        The address 0:0:0:0:0:0:0:0 is called the
204  
        The address 0:0:0:0:0:0:0:0 is called the
206  
        unspecified address. It indicates the
205  
        unspecified address. It indicates the
207  
        absence of an address.
206  
        absence of an address.
208  

207  

209  
        @return `true` if the address is unspecified.
208  
        @return `true` if the address is unspecified.
210  

209  

211  
        @par Specification
210  
        @par Specification
212  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2">
211  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2">
213  
            2.5.2. The Unspecified Address (rfc4291)</a>
212  
            2.5.2. The Unspecified Address (rfc4291)</a>
214  
    */
213  
    */
215  
    bool is_unspecified() const noexcept;
214  
    bool is_unspecified() const noexcept;
216  

215  

217  
    /** Return true if the address is a loopback address.
216  
    /** Return true if the address is a loopback address.
218  

217  

219  
        The unicast address 0:0:0:0:0:0:0:1 is called
218  
        The unicast address 0:0:0:0:0:0:0:1 is called
220  
        the loopback address. It may be used by a node
219  
        the loopback address. It may be used by a node
221  
        to send an IPv6 packet to itself.
220  
        to send an IPv6 packet to itself.
222  

221  

223  
        @return `true` if the address is a loopback address.
222  
        @return `true` if the address is a loopback address.
224  

223  

225  
        @par Specification
224  
        @par Specification
226  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
225  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
227  
            2.5.3. The Loopback Address (rfc4291)</a>
226  
            2.5.3. The Loopback Address (rfc4291)</a>
228  
    */
227  
    */
229  
    bool is_loopback() const noexcept;
228  
    bool is_loopback() const noexcept;
230  

229  

231  
    /** Return true if the address is a mapped IPv4 address.
230  
    /** Return true if the address is a mapped IPv4 address.
232  

231  

233  
        This address type is used to represent the
232  
        This address type is used to represent the
234  
        addresses of IPv4 nodes as IPv6 addresses.
233  
        addresses of IPv4 nodes as IPv6 addresses.
235  

234  

236  
        @return `true` if the address is a mapped IPv4 address.
235  
        @return `true` if the address is a mapped IPv4 address.
237  

236  

238  
        @par Specification
237  
        @par Specification
239  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2">
238  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2">
240  
            2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
239  
            2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
241  
    */
240  
    */
242  
    bool is_v4_mapped() const noexcept;
241  
    bool is_v4_mapped() const noexcept;
243  

242  

244  
    /** Return true if two addresses are equal.
243  
    /** Return true if two addresses are equal.
245  

244  

246  
        @return `true` if the addresses are equal.
245  
        @return `true` if the addresses are equal.
247  
    */
246  
    */
248  
    friend bool
247  
    friend bool
249  
    operator==(ipv6_address const& a1, ipv6_address const& a2) noexcept
248  
    operator==(ipv6_address const& a1, ipv6_address const& a2) noexcept
250  
    {
249  
    {
251  
        return a1.addr_ == a2.addr_;
250  
        return a1.addr_ == a2.addr_;
252  
    }
251  
    }
253  

252  

254  
    /** Return true if two addresses are not equal.
253  
    /** Return true if two addresses are not equal.
255  

254  

256  
        @return `true` if the addresses are not equal.
255  
        @return `true` if the addresses are not equal.
257  
    */
256  
    */
258  
    friend bool
257  
    friend bool
259  
    operator!=(ipv6_address const& a1, ipv6_address const& a2) noexcept
258  
    operator!=(ipv6_address const& a1, ipv6_address const& a2) noexcept
260  
    {
259  
    {
261  
        return a1.addr_ != a2.addr_;
260  
        return a1.addr_ != a2.addr_;
262  
    }
261  
    }
263  

262  

264  
    /** Return an address object that represents the unspecified address.
263  
    /** Return an address object that represents the unspecified address.
265  

264  

266  
        The address 0:0:0:0:0:0:0:0 (::) may be used to bind a socket
265  
        The address 0:0:0:0:0:0:0:0 (::) may be used to bind a socket
267  
        to all available interfaces.
266  
        to all available interfaces.
268  

267  

269  
        @return The unspecified address (::).
268  
        @return The unspecified address (::).
270  
    */
269  
    */
271  
    static ipv6_address any() noexcept
270  
    static ipv6_address any() noexcept
272  
    {
271  
    {
273  
        return ipv6_address();
272  
        return ipv6_address();
274  
    }
273  
    }
275  

274  

276  
    /** Return an address object that represents the loopback address.
275  
    /** Return an address object that represents the loopback address.
277  

276  

278  
        The unicast address 0:0:0:0:0:0:0:1 is called
277  
        The unicast address 0:0:0:0:0:0:0:1 is called
279  
        the loopback address. It may be used by a node
278  
        the loopback address. It may be used by a node
280  
        to send an IPv6 packet to itself.
279  
        to send an IPv6 packet to itself.
281  

280  

282  
        @par Specification
281  
        @par Specification
283  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
282  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
284  
            2.5.3. The Loopback Address (rfc4291)</a>
283  
            2.5.3. The Loopback Address (rfc4291)</a>
285  

284  

286  
        @return The loopback address (::1).
285  
        @return The loopback address (::1).
287  
    */
286  
    */
288  
    static ipv6_address loopback() noexcept;
287  
    static ipv6_address loopback() noexcept;
289  

288  

290  
    /** Format the address to an output stream.
289  
    /** Format the address to an output stream.
291  

290  

292  
        This function writes the address to an
291  
        This function writes the address to an
293  
        output stream using standard notation.
292  
        output stream using standard notation.
294  

293  

295  
        @return The output stream, for chaining.
294  
        @return The output stream, for chaining.
296  

295  

297  
        @param os The output stream to write to.
296  
        @param os The output stream to write to.
298  

297  

299  
        @param addr The address to write.
298  
        @param addr The address to write.
300  
    */
299  
    */
301  
    friend BOOST_COROSIO_DECL std::ostream&
300  
    friend BOOST_COROSIO_DECL std::ostream&
302  
    operator<<(std::ostream& os, ipv6_address const& addr);
301  
    operator<<(std::ostream& os, ipv6_address const& addr);
303  

302  

304  
private:
303  
private:
305  
    std::size_t print_impl(char* dest) const noexcept;
304  
    std::size_t print_impl(char* dest) const noexcept;
306  
};
305  
};
307  

306  

308  
/** Parse a string containing an IPv6 address.
307  
/** Parse a string containing an IPv6 address.
309  

308  

310  
    This function attempts to parse the string
309  
    This function attempts to parse the string
311  
    as an IPv6 address and returns an error code
310  
    as an IPv6 address and returns an error code
312  
    if the string does not contain a valid IPv6 address.
311  
    if the string does not contain a valid IPv6 address.
313  

312  

314  
    @par Exception Safety
313  
    @par Exception Safety
315  
    Throws nothing.
314  
    Throws nothing.
316  

315  

317  
    @return An error code (empty on success).
316  
    @return An error code (empty on success).
318  

317  

319  
    @param s The string to parse.
318  
    @param s The string to parse.
320  
    @param addr The address to store the result.
319  
    @param addr The address to store the result.
321  
*/
320  
*/
322  
[[nodiscard]] BOOST_COROSIO_DECL std::error_code
321  
[[nodiscard]] BOOST_COROSIO_DECL std::error_code
323  
parse_ipv6_address(std::string_view s, ipv6_address& addr) noexcept;
322  
parse_ipv6_address(std::string_view s, ipv6_address& addr) noexcept;
324  

323  

325  
} // namespace boost::corosio
324  
} // namespace boost::corosio
326  

325  

327  
#endif
326  
#endif