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 ipv6_address(bytes_type const& bytes) noexcept;
114  
    explicit ipv6_address(bytes_type const& bytes) noexcept;
115  

115  

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

117  

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

121  

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

123  

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

129  

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

131  

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

136  

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

139  

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

142  

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

145  

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

147  

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

151  

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

156  

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

158  

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

165  

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

167  

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

170  

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

179  

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

181  

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

187  

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

189  

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

191  

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

193  

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

195  

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

198  

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

202  

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

204  

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

208  

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

210  

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

216  

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

218  

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

222  

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

224  

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

230  

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

232  

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

235  

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

237  

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

243  

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

245  

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

253  

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

255  

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

263  

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

265  

266  
        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
267  
        the loopback address. It may be used by a node
267  
        the loopback address. It may be used by a node
268  
        to send an IPv6 packet to itself.
268  
        to send an IPv6 packet to itself.
269  

269  

270  
        @par Specification
270  
        @par Specification
271  
        @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">
272  
            2.5.3. The Loopback Address (rfc4291)</a>
272  
            2.5.3. The Loopback Address (rfc4291)</a>
273  

273  

274  
        @return The loopback address (::1).
274  
        @return The loopback address (::1).
275  
    */
275  
    */
276  
    static ipv6_address loopback() noexcept;
276  
    static ipv6_address loopback() noexcept;
277  

277  

278  
    /** Format the address to an output stream.
278  
    /** Format the address to an output stream.
279  

279  

280  
        This function writes the address to an
280  
        This function writes the address to an
281  
        output stream using standard notation.
281  
        output stream using standard notation.
282  

282  

283  
        @return The output stream, for chaining.
283  
        @return The output stream, for chaining.
284  

284  

285  
        @param os The output stream to write to.
285  
        @param os The output stream to write to.
286  

286  

287  
        @param addr The address to write.
287  
        @param addr The address to write.
288  
    */
288  
    */
289  
    friend BOOST_COROSIO_DECL std::ostream&
289  
    friend BOOST_COROSIO_DECL std::ostream&
290  
    operator<<(std::ostream& os, ipv6_address const& addr);
290  
    operator<<(std::ostream& os, ipv6_address const& addr);
291  

291  

292  
private:
292  
private:
293  
    std::size_t print_impl(char* dest) const noexcept;
293  
    std::size_t print_impl(char* dest) const noexcept;
294  
};
294  
};
295  

295  

296  
/** Parse a string containing an IPv6 address.
296  
/** Parse a string containing an IPv6 address.
297  

297  

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

301  

302  
    @par Exception Safety
302  
    @par Exception Safety
303  
    Throws nothing.
303  
    Throws nothing.
304  

304  

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

306  

307  
    @param s The string to parse.
307  
    @param s The string to parse.
308  
    @param addr The address to store the result.
308  
    @param addr The address to store the result.
309  
*/
309  
*/
310  
[[nodiscard]] BOOST_COROSIO_DECL std::error_code
310  
[[nodiscard]] BOOST_COROSIO_DECL std::error_code
311  
parse_ipv6_address(std::string_view s, ipv6_address& addr) noexcept;
311  
parse_ipv6_address(std::string_view s, ipv6_address& addr) noexcept;
312  

312  

313  
} // namespace boost::corosio
313  
} // namespace boost::corosio
314  

314  

315  
#endif
315  
#endif