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 <iosfwd>
16  
#include <iosfwd>
17  
#include <string>
17  
#include <string>
18  
#include <string_view>
18  
#include <string_view>
19  
#include <system_error>
19  
#include <system_error>
20  

20  

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

22  

23  
class ipv4_address;
23  
class ipv4_address;
24  

24  

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

26  

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

29  

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

41  

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

44  

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

48  

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

54  

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

62  

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

65  

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

76  

77  
    /** 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.
78  

78  

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

82  

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

84  

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

86  

87  
        @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"
88  
            >2.5.2. The Unspecified Address</a>
88  
            >2.5.2. The Unspecified Address</a>
89  

89  

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

94  

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

98  

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

100  

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

104  

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

106  

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

110  

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

114  

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

116  

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

120  

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

122  

123  
        @par Specification
123  
        @par Specification
124  
        @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"
125  
            >2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
125  
            >2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
126  
    */
126  
    */
127  
    explicit ipv6_address(ipv4_address const& addr) noexcept;
127  
    explicit ipv6_address(ipv4_address const& addr) noexcept;
128  

128  

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

130  

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

135  

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

138  

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

141  

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

144  

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

146  

147  
        @par Specification
147  
        @par Specification
148  
        @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"
149  
            >3.2.2. Host (rfc3986)</a>
149  
            >3.2.2. Host (rfc3986)</a>
150  

150  

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

155  

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

157  

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

164  

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

166  

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

169  

170  
        @par Example
170  
        @par Example
171  
        @code
171  
        @code
172  
        ipv6_address::bytes_type b = {{
172  
        ipv6_address::bytes_type b = {{
173  
                0, 1, 0, 2, 0, 3, 0, 4,
173  
                0, 1, 0, 2, 0, 3, 0, 4,
174  
                0, 5, 0, 6, 0, 7, 0, 8 }};
174  
                0, 5, 0, 6, 0, 7, 0, 8 }};
175  
        ipv6_address a(b);
175  
        ipv6_address a(b);
176  
        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");
177  
        @endcode
177  
        @endcode
178  

178  

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

180  

181  
        @par Specification
181  
        @par Specification
182  
        @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">
183  
            2.2. Text Representation of Addresses (rfc4291)</a>
183  
            2.2. Text Representation of Addresses (rfc4291)</a>
184  
    */
184  
    */
185  
    std::string to_string() const;
185  
    std::string to_string() const;
186  

186  

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

188  

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

190  

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

192  

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

194  

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

197  

198  
        @param dest_size The size of the output buffer.
198  
        @param dest_size The size of the output buffer.
199  
    */
199  
    */
200  
    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;
201  

201  

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

203  

204  
        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
205  
        unspecified address. It indicates the
205  
        unspecified address. It indicates the
206  
        absence of an address.
206  
        absence of an address.
207  

207  

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

209  

210  
        @par Specification
210  
        @par Specification
211  
        @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">
212  
            2.5.2. The Unspecified Address (rfc4291)</a>
212  
            2.5.2. The Unspecified Address (rfc4291)</a>
213  
    */
213  
    */
214  
    bool is_unspecified() const noexcept;
214  
    bool is_unspecified() const noexcept;
215  

215  

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

217  

218  
        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
219  
        the loopback address. It may be used by a node
219  
        the loopback address. It may be used by a node
220  
        to send an IPv6 packet to itself.
220  
        to send an IPv6 packet to itself.
221  

221  

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

223  

224  
        @par Specification
224  
        @par Specification
225  
        @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">
226  
            2.5.3. The Loopback Address (rfc4291)</a>
226  
            2.5.3. The Loopback Address (rfc4291)</a>
227  
    */
227  
    */
228  
    bool is_loopback() const noexcept;
228  
    bool is_loopback() const noexcept;
229  

229  

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

231  

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

234  

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

236  

237  
        @par Specification
237  
        @par Specification
238  
        @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">
239  
            2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
239  
            2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
240  
    */
240  
    */
241  
    bool is_v4_mapped() const noexcept;
241  
    bool is_v4_mapped() const noexcept;
242  

242  

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

244  

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

252  

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

254  

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

262  

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

264  

265  
        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
266  
        to all available interfaces.
266  
        to all available interfaces.
267  

267  

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

274  

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

276  

277  
        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
278  
        the loopback address. It may be used by a node
278  
        the loopback address. It may be used by a node
279  
        to send an IPv6 packet to itself.
279  
        to send an IPv6 packet to itself.
280  

280  

281  
        @par Specification
281  
        @par Specification
282  
        @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">
283  
            2.5.3. The Loopback Address (rfc4291)</a>
283  
            2.5.3. The Loopback Address (rfc4291)</a>
284  

284  

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

288  

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

290  

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

293  

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

295  

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

297  

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

302  

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

306  

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

308  

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

312  

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

315  

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

317  

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

323  

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

325  

326  
#endif
326  
#endif