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 the address is a multicast address.
243  
    /** Return true if the address is a multicast address.
244  

244  

245  
        IPv6 multicast addresses have the prefix ff00::/8.
245  
        IPv6 multicast addresses have the prefix ff00::/8.
246  

246  

247  
        @return `true` if the address is a multicast address.
247  
        @return `true` if the address is a multicast address.
248  

248  

249  
        @par Specification
249  
        @par Specification
250  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.7">
250  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.7">
251  
            2.7. Multicast Addresses (rfc4291)</a>
251  
            2.7. Multicast Addresses (rfc4291)</a>
252  
    */
252  
    */
253  
    bool is_multicast() const noexcept;
253  
    bool is_multicast() const noexcept;
254  

254  

255  
    /** Return true if two addresses are equal.
255  
    /** Return true if two addresses are equal.
256  

256  

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

264  

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

266  

267  
        @return `true` if the addresses are not equal.
267  
        @return `true` if the addresses are not equal.
268  
    */
268  
    */
269  
    friend bool
269  
    friend bool
270  
    operator!=(ipv6_address const& a1, ipv6_address const& a2) noexcept
270  
    operator!=(ipv6_address const& a1, ipv6_address const& a2) noexcept
271  
    {
271  
    {
272  
        return a1.addr_ != a2.addr_;
272  
        return a1.addr_ != a2.addr_;
273  
    }
273  
    }
274  

274  

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

276  

277  
        The address 0:0:0:0:0:0:0:0 (::) may be used to bind a socket
277  
        The address 0:0:0:0:0:0:0:0 (::) may be used to bind a socket
278  
        to all available interfaces.
278  
        to all available interfaces.
279  

279  

280  
        @return The unspecified address (::).
280  
        @return The unspecified address (::).
281  
    */
281  
    */
282  
    static ipv6_address any() noexcept
282  
    static ipv6_address any() noexcept
283  
    {
283  
    {
284  
        return ipv6_address();
284  
        return ipv6_address();
285  
    }
285  
    }
286  

286  

287  
    /** Return an address object that represents the loopback address.
287  
    /** Return an address object that represents the loopback address.
288  

288  

289  
        The unicast address 0:0:0:0:0:0:0:1 is called
289  
        The unicast address 0:0:0:0:0:0:0:1 is called
290  
        the loopback address. It may be used by a node
290  
        the loopback address. It may be used by a node
291  
        to send an IPv6 packet to itself.
291  
        to send an IPv6 packet to itself.
292  

292  

293  
        @par Specification
293  
        @par Specification
294  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
294  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
295  
            2.5.3. The Loopback Address (rfc4291)</a>
295  
            2.5.3. The Loopback Address (rfc4291)</a>
296  

296  

297  
        @return The loopback address (::1).
297  
        @return The loopback address (::1).
298  
    */
298  
    */
299  
    static ipv6_address loopback() noexcept;
299  
    static ipv6_address loopback() noexcept;
300  

300  

301  
    /** Format the address to an output stream.
301  
    /** Format the address to an output stream.
302  

302  

303  
        This function writes the address to an
303  
        This function writes the address to an
304  
        output stream using standard notation.
304  
        output stream using standard notation.
305  

305  

306  
        @return The output stream, for chaining.
306  
        @return The output stream, for chaining.
307  

307  

308  
        @param os The output stream to write to.
308  
        @param os The output stream to write to.
309  

309  

310  
        @param addr The address to write.
310  
        @param addr The address to write.
311  
    */
311  
    */
312  
    friend BOOST_COROSIO_DECL std::ostream&
312  
    friend BOOST_COROSIO_DECL std::ostream&
313  
    operator<<(std::ostream& os, ipv6_address const& addr);
313  
    operator<<(std::ostream& os, ipv6_address const& addr);
314  

314  

315  
private:
315  
private:
316  
    std::size_t print_impl(char* dest) const noexcept;
316  
    std::size_t print_impl(char* dest) const noexcept;
317  
};
317  
};
318  

318  

319  
/** Parse a string containing an IPv6 address.
319  
/** Parse a string containing an IPv6 address.
320  

320  

321  
    This function attempts to parse the string
321  
    This function attempts to parse the string
322  
    as an IPv6 address and returns an error code
322  
    as an IPv6 address and returns an error code
323  
    if the string does not contain a valid IPv6 address.
323  
    if the string does not contain a valid IPv6 address.
324  

324  

325  
    @par Exception Safety
325  
    @par Exception Safety
326  
    Throws nothing.
326  
    Throws nothing.
327  

327  

328  
    @return An error code (empty on success).
328  
    @return An error code (empty on success).
329  

329  

330  
    @param s The string to parse.
330  
    @param s The string to parse.
331  
    @param addr The address to store the result.
331  
    @param addr The address to store the result.
332  
*/
332  
*/
333  
[[nodiscard]] BOOST_COROSIO_DECL std::error_code
333  
[[nodiscard]] BOOST_COROSIO_DECL std::error_code
334  
parse_ipv6_address(std::string_view s, ipv6_address& addr) noexcept;
334  
parse_ipv6_address(std::string_view s, ipv6_address& addr) noexcept;
335  

335  

336  
} // namespace boost::corosio
336  
} // namespace boost::corosio
337  

337  

338  
#endif
338  
#endif