1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 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/boostorg/url
7  
// Official repository: https://github.com/boostorg/url
8  
//
8  
//
9  

9  

10  

10  

11  
#include <boost/url/detail/config.hpp>
11  
#include <boost/url/detail/config.hpp>
12  
#include <boost/url/ipv6_address.hpp>
12  
#include <boost/url/ipv6_address.hpp>
13  
#include <boost/url/ipv4_address.hpp>
13  
#include <boost/url/ipv4_address.hpp>
14  
#include <boost/url/rfc/ipv6_address_rule.hpp>
14  
#include <boost/url/rfc/ipv6_address_rule.hpp>
15  
#include <boost/url/detail/except.hpp>
15  
#include <boost/url/detail/except.hpp>
16  
#include <boost/url/grammar/parse.hpp>
16  
#include <boost/url/grammar/parse.hpp>
17  
#include <cstring>
17  
#include <cstring>
18  

18  

19  
namespace boost {
19  
namespace boost {
20  
namespace urls {
20  
namespace urls {
21  

21  

22  
ipv6_address::
22  
ipv6_address::
23  
ipv6_address(
23  
ipv6_address(
24  
    bytes_type const& bytes) noexcept
24  
    bytes_type const& bytes) noexcept
25  
{
25  
{
26  
    std::memcpy(&addr_,
26  
    std::memcpy(&addr_,
27  
        bytes.data(), 16);
27  
        bytes.data(), 16);
28  
}
28  
}
29  

29  

30  
ipv6_address::
30  
ipv6_address::
31  
ipv6_address(
31  
ipv6_address(
32  
    ipv4_address const& addr) noexcept
32  
    ipv4_address const& addr) noexcept
33  
{
33  
{
34  
    auto const v = addr.to_bytes();
34  
    auto const v = addr.to_bytes();
35  
    ipv6_address::bytes_type bytes = {
35  
    ipv6_address::bytes_type bytes = {
36  
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36  
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37  
      0xff, 0xff, v[0], v[1], v[2], v[3] } };
37  
      0xff, 0xff, v[0], v[1], v[2], v[3] } };
38  
    std::memcpy(&addr_, bytes.data(), 16);
38  
    std::memcpy(&addr_, bytes.data(), 16);
39  
}
39  
}
40  

40  

41  
ipv6_address::
41  
ipv6_address::
42  
ipv6_address(
42  
ipv6_address(
43  
    core::string_view s)
43  
    core::string_view s)
44  
    : ipv6_address(
44  
    : ipv6_address(
45  
        parse_ipv6_address(s
45  
        parse_ipv6_address(s
46  
            ).value(BOOST_URL_POS))
46  
            ).value(BOOST_URL_POS))
47  
{
47  
{
48  
}
48  
}
49  

49  

50  
core::string_view
50  
core::string_view
51  
ipv6_address::
51  
ipv6_address::
52  
to_buffer(
52  
to_buffer(
53  
    char* dest,
53  
    char* dest,
54  
    std::size_t dest_size) const
54  
    std::size_t dest_size) const
55  
{
55  
{
56  
    if(dest_size < max_str_len)
56  
    if(dest_size < max_str_len)
57  
        detail::throw_length_error();
57  
        detail::throw_length_error();
58  
    auto n = print_impl(dest);
58  
    auto n = print_impl(dest);
59  
    return core::string_view(dest, n);
59  
    return core::string_view(dest, n);
60  
}
60  
}
61  

61  

62  
bool
62  
bool
63  
ipv6_address::
63  
ipv6_address::
64  
is_loopback() const noexcept
64  
is_loopback() const noexcept
65  
{
65  
{
66  
    return *this == loopback();
66  
    return *this == loopback();
67  
}
67  
}
68  

68  

69  
bool
69  
bool
70  
ipv6_address::
70  
ipv6_address::
71  
is_unspecified() const noexcept
71  
is_unspecified() const noexcept
72  
{
72  
{
73  
    return *this == ipv6_address();
73  
    return *this == ipv6_address();
74  
}
74  
}
75  

75  

76  
bool
76  
bool
77  
ipv6_address::
77  
ipv6_address::
78  
is_v4_mapped() const noexcept
78  
is_v4_mapped() const noexcept
79  
{
79  
{
80  
    return
80  
    return
81  
        addr_[ 0] == 0 && addr_[ 1] == 0 &&
81  
        addr_[ 0] == 0 && addr_[ 1] == 0 &&
82  
        addr_[ 2] == 0 && addr_[ 3] == 0 &&
82  
        addr_[ 2] == 0 && addr_[ 3] == 0 &&
83  
        addr_[ 4] == 0 && addr_[ 5] == 0 &&
83  
        addr_[ 4] == 0 && addr_[ 5] == 0 &&
84  
        addr_[ 6] == 0 && addr_[ 7] == 0 &&
84  
        addr_[ 6] == 0 && addr_[ 7] == 0 &&
85  
        addr_[ 8] == 0 && addr_[ 9] == 0 &&
85  
        addr_[ 8] == 0 && addr_[ 9] == 0 &&
86  
        addr_[10] == 0xff &&
86  
        addr_[10] == 0xff &&
87  
        addr_[11] == 0xff;
87  
        addr_[11] == 0xff;
88  
}
88  
}
89  

89  

90  
ipv6_address
90  
ipv6_address
91  
ipv6_address::
91  
ipv6_address::
92  
loopback() noexcept
92  
loopback() noexcept
93  
{
93  
{
94  
    ipv6_address a;
94  
    ipv6_address a;
95  
    a.addr_[15] = 1;
95  
    a.addr_[15] = 1;
96  
    return a;
96  
    return a;
97  
}
97  
}
98  

98  

99  
void
99  
void
100  
ipv6_address::
100  
ipv6_address::
101  
write_ostream(
101  
write_ostream(
102  
    std::ostream& os) const
102  
    std::ostream& os) const
103  
{
103  
{
104  
    char buf[ipv6_address::max_str_len];
104  
    char buf[ipv6_address::max_str_len];
105  
    auto const s = to_buffer(buf, sizeof(buf));
105  
    auto const s = to_buffer(buf, sizeof(buf));
106  
    os << s;
106  
    os << s;
107  
}
107  
}
108  

108  

109  
std::size_t
109  
std::size_t
110  
ipv6_address::
110  
ipv6_address::
111  
print_impl(
111  
print_impl(
112  
    char* dest) const noexcept
112  
    char* dest) const noexcept
113  
{
113  
{
114  
    auto const count_zeroes =
114  
    auto const count_zeroes =
115  
    []( unsigned char const* first,
115  
    []( unsigned char const* first,
116  
        unsigned char const* const last)
116  
        unsigned char const* const last)
117  
    {
117  
    {
118  
        std::size_t n = 0;
118  
        std::size_t n = 0;
119  
        while(first != last)
119  
        while(first != last)
120  
        {
120  
        {
121  
            if( first[0] != 0 ||
121  
            if( first[0] != 0 ||
122  
                first[1] != 0)
122  
                first[1] != 0)
123  
                break;
123  
                break;
124  
            n += 2;
124  
            n += 2;
125  
            first += 2;
125  
            first += 2;
126  
        }
126  
        }
127  
        return n;
127  
        return n;
128  
    };
128  
    };
129  
    auto const print_hex =
129  
    auto const print_hex =
130  
    []( char* dest,
130  
    []( char* dest,
131  
        unsigned short v)
131  
        unsigned short v)
132  
    {
132  
    {
133  
        char const* const dig =
133  
        char const* const dig =
134  
            "0123456789abcdef";
134  
            "0123456789abcdef";
135  
        if(v >= 0x1000)
135  
        if(v >= 0x1000)
136  
        {
136  
        {
137  
            *dest++ = dig[v>>12];
137  
            *dest++ = dig[v>>12];
138  
            v &= 0x0fff;
138  
            v &= 0x0fff;
139  
            *dest++ = dig[v>>8];
139  
            *dest++ = dig[v>>8];
140  
            v &= 0x0ff;
140  
            v &= 0x0ff;
141  
            *dest++ = dig[v>>4];
141  
            *dest++ = dig[v>>4];
142  
            v &= 0x0f;
142  
            v &= 0x0f;
143  
            *dest++ = dig[v];
143  
            *dest++ = dig[v];
144  
        }
144  
        }
145  
        else if(v >= 0x100)
145  
        else if(v >= 0x100)
146  
        {
146  
        {
147  
            *dest++ = dig[v>>8];
147  
            *dest++ = dig[v>>8];
148  
            v &= 0x0ff;
148  
            v &= 0x0ff;
149  
            *dest++ = dig[v>>4];
149  
            *dest++ = dig[v>>4];
150  
            v &= 0x0f;
150  
            v &= 0x0f;
151  
            *dest++ = dig[v];
151  
            *dest++ = dig[v];
152  
        }
152  
        }
153  
        else if(v >= 0x10)
153  
        else if(v >= 0x10)
154  
        {
154  
        {
155  
            *dest++ = dig[v>>4];
155  
            *dest++ = dig[v>>4];
156  
            v &= 0x0f;
156  
            v &= 0x0f;
157  
            *dest++ = dig[v];
157  
            *dest++ = dig[v];
158  
        }
158  
        }
159  
        else
159  
        else
160  
        {
160  
        {
161  
            *dest++ = dig[v];
161  
            *dest++ = dig[v];
162  
        }
162  
        }
163  
        return dest;
163  
        return dest;
164  
    };
164  
    };
165  
    auto const dest0 = dest;
165  
    auto const dest0 = dest;
166  
    // find longest run of zeroes
166  
    // find longest run of zeroes
167  
    std::size_t best_len = 0;
167  
    std::size_t best_len = 0;
168  
    int best_pos = -1;
168  
    int best_pos = -1;
169  
    auto it = addr_.data();
169  
    auto it = addr_.data();
170  
    auto const v4 =
170  
    auto const v4 =
171  
        is_v4_mapped();
171  
        is_v4_mapped();
172  
    auto const end = v4 ?
172  
    auto const end = v4 ?
173  
        (it + addr_.size() - 4)
173  
        (it + addr_.size() - 4)
174  
        : it + addr_.size();
174  
        : it + addr_.size();
175  
    while(it != end)
175  
    while(it != end)
176  
    {
176  
    {
177  
        auto n = count_zeroes(
177  
        auto n = count_zeroes(
178  
            it, end);
178  
            it, end);
179  
        if(n == 0)
179  
        if(n == 0)
180  
        {
180  
        {
181  
            it += 2;
181  
            it += 2;
182  
            continue;
182  
            continue;
183  
        }
183  
        }
184  
        if(n > best_len)
184  
        if(n > best_len)
185  
        {
185  
        {
186  
            best_pos = static_cast<
186  
            best_pos = static_cast<
187  
                int>(it - addr_.data());
187  
                int>(it - addr_.data());
188  
            best_len = n;
188  
            best_len = n;
189  
        }
189  
        }
190  
        it += n;
190  
        it += n;
191  
    }
191  
    }
192  
    it = addr_.data();
192  
    it = addr_.data();
193  
    if(best_pos != 0)
193  
    if(best_pos != 0)
194  
    {
194  
    {
195  
        unsigned short v =
195  
        unsigned short v =
196  
            (it[0] * 256U) + it[1];
196  
            (it[0] * 256U) + it[1];
197  
        dest = print_hex(dest, v);
197  
        dest = print_hex(dest, v);
198  
        it += 2;
198  
        it += 2;
199  
    }
199  
    }
200  
    else
200  
    else
201  
    {
201  
    {
202  
        *dest++ = ':';
202  
        *dest++ = ':';
203  
        it += best_len;
203  
        it += best_len;
204  
        if(it == end)
204  
        if(it == end)
205  
            *dest++ = ':';
205  
            *dest++ = ':';
206  
    }
206  
    }
207  
    while(it != end)
207  
    while(it != end)
208  
    {
208  
    {
209  
        *dest++ = ':';
209  
        *dest++ = ':';
210  
        if(it - addr_.data() ==
210  
        if(it - addr_.data() ==
211  
            best_pos)
211  
            best_pos)
212  
        {
212  
        {
213  
            it += best_len;
213  
            it += best_len;
214  
            if(it == end)
214  
            if(it == end)
215  
                *dest++ = ':';
215  
                *dest++ = ':';
216  
            continue;
216  
            continue;
217  
        }
217  
        }
218  
        unsigned short v =
218  
        unsigned short v =
219  
            (it[0] * 256U) + it[1];
219  
            (it[0] * 256U) + it[1];
220  
        dest = print_hex(dest, v);
220  
        dest = print_hex(dest, v);
221  
        it += 2;
221  
        it += 2;
222  
    }
222  
    }
223  
    if(v4)
223  
    if(v4)
224  
    {
224  
    {
225  
        ipv4_address::bytes_type bytes;
225  
        ipv4_address::bytes_type bytes;
226  
        bytes[0] = it[0];
226  
        bytes[0] = it[0];
227  
        bytes[1] = it[1];
227  
        bytes[1] = it[1];
228  
        bytes[2] = it[2];
228  
        bytes[2] = it[2];
229  
        bytes[3] = it[3];
229  
        bytes[3] = it[3];
230  
        ipv4_address a(bytes);
230  
        ipv4_address a(bytes);
231  
        *dest++ = ':';
231  
        *dest++ = ':';
232  
        dest += a.print_impl(dest);
232  
        dest += a.print_impl(dest);
233  
    }
233  
    }
234  
    return dest - dest0;
234  
    return dest - dest0;
235  
}
235  
}
236  

236  

237  
void
237  
void
238  
ipv6_address::
238  
ipv6_address::
239  
to_string_impl(
239  
to_string_impl(
240  
    string_token::arg& t) const
240  
    string_token::arg& t) const
241  
{
241  
{
242  
    char buf[max_str_len];
242  
    char buf[max_str_len];
243  
    auto const n = print_impl(buf);
243  
    auto const n = print_impl(buf);
244  
    char* dest = t.prepare(n);
244  
    char* dest = t.prepare(n);
245  
    std::memcpy(dest, buf, n);
245  
    std::memcpy(dest, buf, n);
246  
}
246  
}
247  

247  

248  
//------------------------------------------------
248  
//------------------------------------------------
249  

249  

250  
auto
250  
auto
251  
parse_ipv6_address(
251  
parse_ipv6_address(
252  
    core::string_view s) noexcept ->
252  
    core::string_view s) noexcept ->
253  
        system::result<ipv6_address>
253  
        system::result<ipv6_address>
254  
{
254  
{
255  
    return grammar::parse(
255  
    return grammar::parse(
256  
        s, ipv6_address_rule);
256  
        s, ipv6_address_rule);
257  
}
257  
}
258  

258  

259  
} // urls
259  
} // urls
260  
} // boost
260  
} // boost
261  

261