1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
3  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
//
7  
//
8  
// Official repository: https://github.com/boostorg/url
8  
// Official repository: https://github.com/boostorg/url
9  
//
9  
//
10  

10  

11  
#ifndef BOOST_URL_IPV4_ADDRESS_HPP
11  
#ifndef BOOST_URL_IPV4_ADDRESS_HPP
12  
#define BOOST_URL_IPV4_ADDRESS_HPP
12  
#define BOOST_URL_IPV4_ADDRESS_HPP
13  

13  

14  
#include <boost/url/detail/config.hpp>
14  
#include <boost/url/detail/config.hpp>
15  
#include <boost/url/error.hpp>
15  
#include <boost/url/error.hpp>
16  
#include <boost/url/error_types.hpp>
16  
#include <boost/url/error_types.hpp>
17  
#include <boost/core/detail/string_view.hpp>
17  
#include <boost/core/detail/string_view.hpp>
18  
#include <boost/url/grammar/string_token.hpp>
18  
#include <boost/url/grammar/string_token.hpp>
19  
#include <string>
19  
#include <string>
20  
#include <array>
20  
#include <array>
21  
#include <cstdint>
21  
#include <cstdint>
22  
#include <iosfwd>
22  
#include <iosfwd>
23  

23  

24  
namespace boost {
24  
namespace boost {
25  
namespace urls {
25  
namespace urls {
26  

26  

27  
/** An IP version 4 style address.
27  
/** An IP version 4 style address.
28  

28  

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

31  

32  
    @par BNF
32  
    @par BNF
33  
    @code
33  
    @code
34  
    IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
34  
    IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
35  

35  

36  
    dec-octet   = DIGIT                 ; 0-9
36  
    dec-octet   = DIGIT                 ; 0-9
37  
                / %x31-39 DIGIT         ; 10-99
37  
                / %x31-39 DIGIT         ; 10-99
38  
                / "1" 2DIGIT            ; 100-199
38  
                / "1" 2DIGIT            ; 100-199
39  
                / "2" %x30-34 DIGIT     ; 200-249
39  
                / "2" %x30-34 DIGIT     ; 200-249
40  
                / "25" %x30-35          ; 250-255
40  
                / "25" %x30-35          ; 250-255
41  
    @endcode
41  
    @endcode
42  

42  

43  
    @par Specification
43  
    @par Specification
44  
    @li <a href="https://en.wikipedia.org/wiki/IPv4"
44  
    @li <a href="https://en.wikipedia.org/wiki/IPv4"
45  
        >IPv4 (Wikipedia)</a>
45  
        >IPv4 (Wikipedia)</a>
46  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
46  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
47  
        >3.2.2. Host (rfc3986)</a>
47  
        >3.2.2. Host (rfc3986)</a>
48  

48  

49  
    @see
49  
    @see
50  
        @ref parse_ipv4_address,
50  
        @ref parse_ipv4_address,
51  
        @ref ipv6_address.
51  
        @ref ipv6_address.
52  
*/
52  
*/
53  
class ipv4_address
53  
class ipv4_address
54  
{
54  
{
55  
public:
55  
public:
56  
    /** The number of characters in the longest possible IPv4 string.
56  
    /** The number of characters in the longest possible IPv4 string.
57  

57  

58  
        The longest ipv4 address string is "255.255.255.255".
58  
        The longest ipv4 address string is "255.255.255.255".
59  
    */
59  
    */
60  
    static
60  
    static
61  
    constexpr
61  
    constexpr
62  
    std::size_t max_str_len = 15;
62  
    std::size_t max_str_len = 15;
63  

63  

64  
    /** The type used to represent an address as an unsigned integer
64  
    /** The type used to represent an address as an unsigned integer
65  
    */
65  
    */
66  
    using uint_type =
66  
    using uint_type =
67  
        std::uint_least32_t;
67  
        std::uint_least32_t;
68  

68  

69  
    /** The type used to represent an address as an array of bytes
69  
    /** The type used to represent an address as an array of bytes
70  
    */
70  
    */
71  
    using bytes_type =
71  
    using bytes_type =
72  
        std::array<unsigned char, 4>;
72  
        std::array<unsigned char, 4>;
73  

73  

74  
    /** Constructor.
74  
    /** Constructor.
75  
    */
75  
    */
76  
    ipv4_address() = default;
76  
    ipv4_address() = default;
77  

77  

78  
    /** Constructor.
78  
    /** Constructor.
79  
    */
79  
    */
80  
    ipv4_address(
80  
    ipv4_address(
81  
        ipv4_address const&) = default;
81  
        ipv4_address const&) = default;
82  

82  

83  
    /** Copy Assignment.
83  
    /** Copy Assignment.
84  

84  

85  
        @param other The object to copy.
85  
        @param other The object to copy.
86  
        @return A reference to this object.
86  
        @return A reference to this object.
87  
    */
87  
    */
88  
    ipv4_address&
88  
    ipv4_address&
89  
    operator=(
89  
    operator=(
90  
        ipv4_address const& other) = default;
90  
        ipv4_address const& other) = default;
91  

91  

92  
    //
92  
    //
93  
    //---
93  
    //---
94  
    //
94  
    //
95  

95  

96  
    /** Construct from an unsigned integer.
96  
    /** Construct from an unsigned integer.
97  

97  

98  
        This function constructs an address from
98  
        This function constructs an address from
99  
        the unsigned integer `u`, where the most
99  
        the unsigned integer `u`, where the most
100  
        significant byte forms the first octet
100  
        significant byte forms the first octet
101  
        of the resulting address.
101  
        of the resulting address.
102  

102  

103  
        @param u The integer to construct from.
103  
        @param u The integer to construct from.
104  
    */
104  
    */
105  
    BOOST_URL_DECL
105  
    BOOST_URL_DECL
106  
    explicit
106  
    explicit
107  
    ipv4_address(
107  
    ipv4_address(
108  
        uint_type u) noexcept;
108  
        uint_type u) noexcept;
109  

109  

110  
    /** Construct from an array of bytes.
110  
    /** Construct from an array of bytes.
111  

111  

112  
        This function constructs an address
112  
        This function constructs an address
113  
        from the array in `bytes`, which is
113  
        from the array in `bytes`, which is
114  
        interpreted in big-endian.
114  
        interpreted in big-endian.
115  

115  

116  
        @param bytes The value to construct from.
116  
        @param bytes The value to construct from.
117  
    */
117  
    */
118  
    BOOST_URL_DECL
118  
    BOOST_URL_DECL
119  
    explicit
119  
    explicit
120  
    ipv4_address(
120  
    ipv4_address(
121  
        bytes_type const& bytes) noexcept;
121  
        bytes_type const& bytes) noexcept;
122  

122  

123  
    /** Construct from a string.
123  
    /** Construct from a string.
124  

124  

125  
        This function constructs an address from
125  
        This function constructs an address from
126  
        the string `s`, which must contain a valid
126  
        the string `s`, which must contain a valid
127  
        IPv4 address string or else an exception
127  
        IPv4 address string or else an exception
128  
        is thrown.
128  
        is thrown.
129  

129  

130  
        @note For a non-throwing parse function,
130  
        @note For a non-throwing parse function,
131  
        use @ref parse_ipv4_address.
131  
        use @ref parse_ipv4_address.
132  

132  

133  
        @par Exception Safety
133  
        @par Exception Safety
134  
        Exceptions thrown on invalid input.
134  
        Exceptions thrown on invalid input.
135  

135  

136  
        @throw system_error The input failed to parse correctly.
136  
        @throw system_error The input failed to parse correctly.
137  

137  

138  
        @param s The string to parse.
138  
        @param s The string to parse.
139  

139  

140  
        @par Specification
140  
        @par Specification
141  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
141  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
142  
            >3.2.2. Host (rfc3986)</a>
142  
            >3.2.2. Host (rfc3986)</a>
143  

143  

144  
        @see
144  
        @see
145  
            @ref parse_ipv4_address.
145  
            @ref parse_ipv4_address.
146  
    */
146  
    */
147  
    BOOST_URL_DECL
147  
    BOOST_URL_DECL
148  
    explicit
148  
    explicit
149  
    ipv4_address(
149  
    ipv4_address(
150  
        core::string_view s);
150  
        core::string_view s);
151  

151  

152  
    /** Return the address as bytes, in network byte order.
152  
    /** Return the address as bytes, in network byte order.
153  

153  

154  
        @return The address as an array of bytes.
154  
        @return The address as an array of bytes.
155  
    */
155  
    */
156  
    BOOST_URL_DECL
156  
    BOOST_URL_DECL
157  
    bytes_type
157  
    bytes_type
158  
    to_bytes() const noexcept;
158  
    to_bytes() const noexcept;
159  

159  

160  
    /** Return the address as an unsigned integer.
160  
    /** Return the address as an unsigned integer.
161  

161  

162  
        @return The address as an unsigned integer.
162  
        @return The address as an unsigned integer.
163  
    */
163  
    */
164  
    BOOST_URL_DECL
164  
    BOOST_URL_DECL
165  
    uint_type
165  
    uint_type
166  
    to_uint() const noexcept;
166  
    to_uint() const noexcept;
167  

167  

168  
    /** Return the address as a string in dotted decimal format
168  
    /** Return the address as a string in dotted decimal format
169  

169  

170  
        When called with no arguments, the
170  
        When called with no arguments, the
171  
        return type is `std::string`.
171  
        return type is `std::string`.
172  
        Otherwise, the return type and style
172  
        Otherwise, the return type and style
173  
        of output is determined by which string
173  
        of output is determined by which string
174  
        token is passed.
174  
        token is passed.
175  

175  

176  
        @par Example
176  
        @par Example
177  
        @code
177  
        @code
178  
        assert( ipv4_address(0x01020304).to_string() == "1.2.3.4" );
178  
        assert( ipv4_address(0x01020304).to_string() == "1.2.3.4" );
179  
        @endcode
179  
        @endcode
180  

180  

181  
        @par Complexity
181  
        @par Complexity
182  
        Constant.
182  
        Constant.
183  

183  

184  
        @par Exception Safety
184  
        @par Exception Safety
185  
        Strong guarantee.
185  
        Strong guarantee.
186  
        Calls to allocate may throw.
186  
        Calls to allocate may throw.
187  
        String tokens may throw exceptions.
187  
        String tokens may throw exceptions.
188  

188  

189  
        @return The return type of the string token.
189  
        @return The return type of the string token.
190  
        If the token parameter is omitted, then
190  
        If the token parameter is omitted, then
191  
        a new `std::string` is returned.
191  
        a new `std::string` is returned.
192  
        Otherwise, the function return type
192  
        Otherwise, the function return type
193  
        is the result type of the token.
193  
        is the result type of the token.
194  

194  

195  
        @param token An optional string token.
195  
        @param token An optional string token.
196  

196  

197  
        @par Specification
197  
        @par Specification
198  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2">
198  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2">
199  
            2.2. Text Representation of Addresses (rfc4291)</a>
199  
            2.2. Text Representation of Addresses (rfc4291)</a>
200  
    */
200  
    */
201  
    template<BOOST_URL_STRTOK_TPARAM>
201  
    template<BOOST_URL_STRTOK_TPARAM>
202  
    BOOST_URL_STRTOK_RETURN
202  
    BOOST_URL_STRTOK_RETURN
203  
    to_string(StringToken&& token = {}) const
203  
    to_string(StringToken&& token = {}) const
204  
    {
204  
    {
205  
        to_string_impl(token);
205  
        to_string_impl(token);
206  
        return token.result();
206  
        return token.result();
207  
    }
207  
    }
208  

208  

209  
    /** Write a dotted decimal string representing the address to a buffer
209  
    /** Write a dotted decimal string representing the address to a buffer
210  

210  

211  
        The resulting buffer is not null-terminated.
211  
        The resulting buffer is not null-terminated.
212  

212  

213  
        @throw std::length_error `dest_size < ipv4_address::max_str_len`
213  
        @throw std::length_error `dest_size < ipv4_address::max_str_len`
214  

214  

215  
        @return The formatted string
215  
        @return The formatted string
216  

216  

217  
        @param dest The buffer in which to write,
217  
        @param dest The buffer in which to write,
218  
        which must have at least `dest_size` space.
218  
        which must have at least `dest_size` space.
219  

219  

220  
        @param dest_size The size of the output buffer.
220  
        @param dest_size The size of the output buffer.
221  
    */
221  
    */
222  
    BOOST_URL_DECL
222  
    BOOST_URL_DECL
223  
    core::string_view
223  
    core::string_view
224  
    to_buffer(
224  
    to_buffer(
225  
        char* dest,
225  
        char* dest,
226  
        std::size_t dest_size) const;
226  
        std::size_t dest_size) const;
227  

227  

228  
    /** Return true if the address is a loopback address
228  
    /** Return true if the address is a loopback address
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  
    BOOST_URL_DECL
232  
    BOOST_URL_DECL
233  
    bool
233  
    bool
234  
    is_loopback() const noexcept;
234  
    is_loopback() const noexcept;
235  

235  

236  
    /** Return true if the address is unspecified
236  
    /** Return true if the address is unspecified
237  

237  

238  
        @return `true` if the address is unspecified
238  
        @return `true` if the address is unspecified
239  
    */
239  
    */
240  
    BOOST_URL_DECL
240  
    BOOST_URL_DECL
241  
    bool
241  
    bool
242  
    is_unspecified() const noexcept;
242  
    is_unspecified() const noexcept;
243  

243  

244  
    /** Return true if the address is a multicast address
244  
    /** Return true if the address is a multicast address
245  

245  

246  
        @return `true` if the address is a multicast address
246  
        @return `true` if the address is a multicast address
247  
    */
247  
    */
248  
    BOOST_URL_DECL
248  
    BOOST_URL_DECL
249  
    bool
249  
    bool
250  
    is_multicast() const noexcept;
250  
    is_multicast() const noexcept;
251  

251  

252  
    /** Return true if two addresses are equal
252  
    /** Return true if two addresses are equal
253  

253  

254  
        @param a1 The first address to compare.
254  
        @param a1 The first address to compare.
255  
        @param a2 The second address to compare.
255  
        @param a2 The second address to compare.
256  
        @return `true` if the addresses are equal, otherwise `false`.
256  
        @return `true` if the addresses are equal, otherwise `false`.
257  

257  

258  
    */
258  
    */
259  
    friend
259  
    friend
260  
    bool
260  
    bool
261  
    operator==(
261  
    operator==(
262  
        ipv4_address const& a1,
262  
        ipv4_address const& a1,
263  
        ipv4_address const& a2) noexcept
263  
        ipv4_address const& a2) noexcept
264  
    {
264  
    {
265  
        return a1.addr_ == a2.addr_;
265  
        return a1.addr_ == a2.addr_;
266  
    }
266  
    }
267  

267  

268  
    /** Return true if two addresses are not equal
268  
    /** Return true if two addresses are not equal
269  

269  

270  
        @param a1 The first address to compare.
270  
        @param a1 The first address to compare.
271  
        @param a2 The second address to compare.
271  
        @param a2 The second address to compare.
272  
        @return `true` if the addresses are not equal, otherwise `false`.
272  
        @return `true` if the addresses are not equal, otherwise `false`.
273  
    */
273  
    */
274  
    friend
274  
    friend
275  
    bool
275  
    bool
276  
    operator!=(
276  
    operator!=(
277  
        ipv4_address const& a1,
277  
        ipv4_address const& a1,
278  
        ipv4_address const& a2) noexcept
278  
        ipv4_address const& a2) noexcept
279  
    {
279  
    {
280  
        return a1.addr_ != a2.addr_;
280  
        return a1.addr_ != a2.addr_;
281  
    }
281  
    }
282  

282  

283  
    /** Return an address object that represents any address
283  
    /** Return an address object that represents any address
284  

284  

285  
        @return The any address.
285  
        @return The any address.
286  
    */
286  
    */
287  
    static
287  
    static
288  
    ipv4_address
288  
    ipv4_address
289  
    any() noexcept
289  
    any() noexcept
290  
    {
290  
    {
291  
        return ipv4_address();
291  
        return ipv4_address();
292  
    }
292  
    }
293  

293  

294  
    /** Return an address object that represents the loopback address
294  
    /** Return an address object that represents the loopback address
295  

295  

296  
        @return The loopback address.
296  
        @return The loopback address.
297  
    */
297  
    */
298  
    static
298  
    static
299  
    ipv4_address
299  
    ipv4_address
300  
    loopback() noexcept
300  
    loopback() noexcept
301  
    {
301  
    {
302  
        return ipv4_address(0x7F000001);
302  
        return ipv4_address(0x7F000001);
303  
    }
303  
    }
304  

304  

305  
    /** Return an address object that represents the broadcast address
305  
    /** Return an address object that represents the broadcast address
306  

306  

307  
        @return The broadcast address.
307  
        @return The broadcast address.
308  
    */
308  
    */
309  
    static
309  
    static
310  
    ipv4_address
310  
    ipv4_address
311  
    broadcast() noexcept
311  
    broadcast() noexcept
312  
    {
312  
    {
313  
        return ipv4_address(0xFFFFFFFF);
313  
        return ipv4_address(0xFFFFFFFF);
314  
    }
314  
    }
315  

315  

316  
/** Format the address to an output stream.
316  
/** Format the address to an output stream.
317  

317  

318  
    IPv4 addresses written to output streams
318  
    IPv4 addresses written to output streams
319  
    are written in their dotted decimal format.
319  
    are written in their dotted decimal format.
320  

320  

321  
    @param os The output stream.
321  
    @param os The output stream.
322  
    @param addr The address to format.
322  
    @param addr The address to format.
323  
    @return The output stream.
323  
    @return The output stream.
324  
*/
324  
*/
325  
    friend
325  
    friend
326  
    std::ostream&
326  
    std::ostream&
327  
    operator<<(
327  
    operator<<(
328  
        std::ostream& os,
328  
        std::ostream& os,
329  
        ipv4_address const& addr)
329  
        ipv4_address const& addr)
330  
    {
330  
    {
331  
        addr.write_ostream(os);
331  
        addr.write_ostream(os);
332  
        return os;
332  
        return os;
333  
    }
333  
    }
334  

334  

335  
private:
335  
private:
336  
    friend class ipv6_address;
336  
    friend class ipv6_address;
337  

337  

338  
    BOOST_URL_DECL void write_ostream(std::ostream&) const;
338  
    BOOST_URL_DECL void write_ostream(std::ostream&) const;
339  

339  

340  
    BOOST_URL_DECL
340  
    BOOST_URL_DECL
341  
    std::size_t
341  
    std::size_t
342  
    print_impl(
342  
    print_impl(
343  
        char* dest) const noexcept;
343  
        char* dest) const noexcept;
344  

344  

345  
    BOOST_URL_DECL
345  
    BOOST_URL_DECL
346  
    void
346  
    void
347  
    to_string_impl(
347  
    to_string_impl(
348  
        string_token::arg& t) const;
348  
        string_token::arg& t) const;
349  

349  

350  
    uint_type addr_ = 0;
350  
    uint_type addr_ = 0;
351  
};
351  
};
352  

352  

353  
//------------------------------------------------
353  
//------------------------------------------------
354  

354  

355  
/** Return an IPv4 address from an IP address string in dotted decimal form
355  
/** Return an IPv4 address from an IP address string in dotted decimal form
356  

356  

357  
    @param s The string to parse.
357  
    @param s The string to parse.
358  
    @return The parsed address, or an error code.
358  
    @return The parsed address, or an error code.
359  
*/
359  
*/
360  
BOOST_URL_DECL
360  
BOOST_URL_DECL
361  
system::result<ipv4_address>
361  
system::result<ipv4_address>
362  
parse_ipv4_address(
362  
parse_ipv4_address(
363  
    core::string_view s) noexcept;
363  
    core::string_view s) noexcept;
364  

364  

365  
} // urls
365  
} // urls
366  
} // boost
366  
} // boost
367  

367  

368  
#endif
368  
#endif