1  
//
1  
//
2  
// Copyright (c) 2026 Vinnie Falco (vinnie dot falco at gmail dot com)
2  
// Copyright (c) 2026 Vinnie Falco (vinnie dot falco at gmail dot 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
115  
    ipv6_address(bytes_type const& bytes) noexcept;
115  
    ipv6_address(bytes_type const& bytes) noexcept;
116  

116  

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

118  

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

122  

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

124  

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

131  

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

133  

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

138  

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

141  

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

144  

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

147  

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

149  

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

153  

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

159  

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

161  

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

169  

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

171  

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

174  

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

183  

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

185  

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

192  

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

194  

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

196  

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

198  

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

200  

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

203  

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

208  

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

210  

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

214  

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

216  

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

223  

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

225  

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

229  

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

231  

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

238  

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

240  

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

243  

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

245  

246  
        @par Specification
246  
        @par Specification
247  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2">
247  
        @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>
248  
            2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
249  
    */
249  
    */
250  
    bool
250  
    bool
251  
    is_v4_mapped() const noexcept;
251  
    is_v4_mapped() const noexcept;
252  

252  

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

254  

255  
        @return `true` if the addresses are equal.
255  
        @return `true` if the addresses are equal.
256  
    */
256  
    */
257  
    friend
257  
    friend
258  
    bool
258  
    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 true if two addresses are not equal.
264  
    /** Return true if two addresses are not equal.
265  

265  

266  
        @return `true` if the addresses are not equal.
266  
        @return `true` if the addresses are not equal.
267  
    */
267  
    */
268  
    friend
268  
    friend
269  
    bool
269  
    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 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
287  
    static
288  
    ipv6_address
288  
    ipv6_address
289  
    loopback() noexcept;
289  
    loopback() noexcept;
290  

290  

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

292  

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

295  

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

297  

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

299  

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

306  

307  
private:
307  
private:
308  
    std::size_t
308  
    std::size_t
309  
    print_impl(char* dest) const noexcept;
309  
    print_impl(char* dest) const noexcept;
310  
};
310  
};
311  

311  

312  
//------------------------------------------------
312  
//------------------------------------------------
313  

313  

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

315  

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

319  

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

322  

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

324  

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

333  

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

335  

336  
#endif
336  
#endif