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 <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  
class ipv4_address;
24  
class ipv4_address;
25  

25  

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

27  

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

30  

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

42  

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

45  

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

49  

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

55  

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

63  

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

66  

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

77  

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

79  

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

83  

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

85  

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

87  

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

90  

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

95  

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

99  

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

101  

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

105  

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

107  

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

111  

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

115  

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

117  

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

121  

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

123  

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

129  

132  
    /** Construct from a string.
130  
    /** Construct from a string.
133  

131  

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

136  

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

139  

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

142  

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

145  

148  
        @param s The string to parse.
146  
        @param s The string to parse.
149  

147  

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

151  

154  
        @see
152  
        @see
155  
            @ref parse_ipv6_address.
153  
            @ref parse_ipv6_address.
156  
    */
154  
    */
157 -
    explicit
155 +
    explicit ipv6_address(std::string_view s);
158 -
    ipv6_address(std::string_view s);
 
159  

156  

160  
    /** Return the address as bytes, in network byte order.
157  
    /** Return the address as bytes, in network byte order.
161  

158  

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

165  

170  
    /** Return the address as a string.
166  
    /** Return the address as a string.
171  

167  

172  
        The returned string does not
168  
        The returned string does not
173  
        contain surrounding square brackets.
169  
        contain surrounding square brackets.
174  

170  

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

179  

184  
        @return The address as a string.
180  
        @return The address as a string.
185  

181  

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

187  

193  
    /** Write a string representing the address to a buffer.
188  
    /** Write a string representing the address to a buffer.
194  

189  

195  
        The resulting buffer is not null-terminated.
190  
        The resulting buffer is not null-terminated.
196  

191  

197  
        @throw std::length_error `dest_size < ipv6_address::max_str_len`
192  
        @throw std::length_error `dest_size < ipv6_address::max_str_len`
198  

193  

199  
        @return The formatted string view.
194  
        @return The formatted string view.
200  

195  

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

198  

204  
        @param dest_size The size of the output buffer.
199  
        @param dest_size The size of the output buffer.
205  
    */
200  
    */
206 -
    std::string_view
201 +
    std::string_view to_buffer(char* dest, std::size_t dest_size) const;
207 -
    to_buffer(char* dest, std::size_t dest_size) const;
 
208  

202  

209  
    /** Return true if the address is unspecified.
203  
    /** Return true if the address is unspecified.
210  

204  

211  
        The address 0:0:0:0:0:0:0:0 is called the
205  
        The address 0:0:0:0:0:0:0:0 is called the
212  
        unspecified address. It indicates the
206  
        unspecified address. It indicates the
213  
        absence of an address.
207  
        absence of an address.
214  

208  

215  
        @return `true` if the address is unspecified.
209  
        @return `true` if the address is unspecified.
216  

210  

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

216  

224  
    /** Return true if the address is a loopback address.
217  
    /** Return true if the address is a loopback address.
225  

218  

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

222  

230  
        @return `true` if the address is a loopback address.
223  
        @return `true` if the address is a loopback address.
231  

224  

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

230  

239  
    /** Return true if the address is a mapped IPv4 address.
231  
    /** Return true if the address is a mapped IPv4 address.
240  

232  

241  
        This address type is used to represent the
233  
        This address type is used to represent the
242  
        addresses of IPv4 nodes as IPv6 addresses.
234  
        addresses of IPv4 nodes as IPv6 addresses.
243  

235  

244  
        @return `true` if the address is a mapped IPv4 address.
236  
        @return `true` if the address is a mapped IPv4 address.
245  

237  

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

243  

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

245  

255  
        @return `true` if the addresses are equal.
246  
        @return `true` if the addresses are equal.
256  
    */
247  
    */
257 -
    friend
248 +
    friend bool
258 -
    bool
 
259  
    operator==(ipv6_address const& a1, ipv6_address const& a2) noexcept
249  
    operator==(ipv6_address const& a1, ipv6_address const& a2) noexcept
260  
    {
250  
    {
261  
        return a1.addr_ == a2.addr_;
251  
        return a1.addr_ == a2.addr_;
262  
    }
252  
    }
263  

253  

264  
    /** Return true if two addresses are not equal.
254  
    /** Return true if two addresses are not equal.
265  

255  

266  
        @return `true` if the addresses are not equal.
256  
        @return `true` if the addresses are not equal.
267  
    */
257  
    */
268 -
    friend
258 +
    friend bool
269 -
    bool
 
270  
    operator!=(ipv6_address const& a1, ipv6_address const& a2) noexcept
259  
    operator!=(ipv6_address const& a1, ipv6_address const& a2) noexcept
271  
    {
260  
    {
272  
        return a1.addr_ != a2.addr_;
261  
        return a1.addr_ != a2.addr_;
273  
    }
262  
    }
274  

263  

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

265  

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

269  

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

273  

285  
        @return The loopback address (::1).
274  
        @return The loopback address (::1).
286  
    */
275  
    */
287 -
    static
276 +
    static ipv6_address loopback() noexcept;
288 -
    ipv6_address
 
289 -
    loopback() noexcept;
 
290  

277  

291  
    /** Format the address to an output stream.
278  
    /** Format the address to an output stream.
292  

279  

293  
        This function writes the address to an
280  
        This function writes the address to an
294  
        output stream using standard notation.
281  
        output stream using standard notation.
295  

282  

296  
        @return The output stream, for chaining.
283  
        @return The output stream, for chaining.
297  

284  

298  
        @param os The output stream to write to.
285  
        @param os The output stream to write to.
299  

286  

300  
        @param addr The address to write.
287  
        @param addr The address to write.
301  
    */
288  
    */
302 -
    friend
289 +
    friend BOOST_COROSIO_DECL std::ostream&
303 -
    BOOST_COROSIO_DECL
 
304 -
    std::ostream&
 
305  
    operator<<(std::ostream& os, ipv6_address const& addr);
290  
    operator<<(std::ostream& os, ipv6_address const& addr);
306  

291  

307  
private:
292  
private:
308 -
    std::size_t
293 +
    std::size_t print_impl(char* dest) const noexcept;
309 -
    print_impl(char* dest) const noexcept;
 
310  
};
294  
};
311 -
//------------------------------------------------
 
312  

295  

313  

296  

314  
/** Parse a string containing an IPv6 address.
297  
/** Parse a string containing an IPv6 address.
315  

298  

316  
    This function attempts to parse the string
299  
    This function attempts to parse the string
317  
    as an IPv6 address and returns an error code
300  
    as an IPv6 address and returns an error code
318  
    if the string does not contain a valid IPv6 address.
301  
    if the string does not contain a valid IPv6 address.
319  

302  

320  
    @par Exception Safety
303  
    @par Exception Safety
321  
    Throws nothing.
304  
    Throws nothing.
322  

305  

323  
    @return An error code (empty on success).
306  
    @return An error code (empty on success).
324  

307  

325  
    @param s The string to parse.
308  
    @param s The string to parse.
326  
    @param addr The address to store the result.
309  
    @param addr The address to store the result.
327  
*/
310  
*/
328 -
[[nodiscard]] BOOST_COROSIO_DECL
311 +
[[nodiscard]] BOOST_COROSIO_DECL std::error_code
329 -
std::error_code
312 +
parse_ipv6_address(std::string_view s, ipv6_address& addr) noexcept;
330 -
parse_ipv6_address(
 
331 -
    std::string_view s,
 
332 -
    ipv6_address& addr) noexcept;
 
333  

313  

334  
} // namespace boost::corosio
314  
} // namespace boost::corosio
335  

315  

336  
#endif
316  
#endif