aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/ipv6_address/ipv6_address.h
blob: a6ca43a84365e8c3f33c46a67935209f60b4625e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#pragma once

#include <util/generic/hash_set.h>
#include <util/network/ip.h>
#include <util/stream/input.h>

#include <library/cpp/int128/int128.h>

#if defined(_freebsd_)
// #include required to avoid problem with undefined 'socklen_t' on FreeBSD
#include <sys/socket.h>
#endif

#if defined(_win_)
// #include required to avoid problem with undefined 'socklen_t' on Windows
#include <util/network/socket.h>
#endif

namespace NAddr {
    class IRemoteAddr;
}
struct in6_addr;
struct in_addr;
struct sockaddr;
struct sockaddr_in;
struct sockaddr_in6;

// TODO (dimanne): rename to something like TIntInetAddress or THostAddress
class TIpv6Address {
public:
    enum TIpType { Ipv6,
                   Ipv4,
                   LAST };

    constexpr TIpv6Address() noexcept = default;
    constexpr TIpv6Address(const TIpv6Address&) noexcept = default;
    constexpr TIpv6Address& operator=(const TIpv6Address&) noexcept = default;

    constexpr TIpv6Address(const ui128& ip, TIpType Type) noexcept
        : Ip(ip), Type_(Type)
    {}

    constexpr TIpv6Address(ui8 a, ui8 b, ui8 c, ui8 d) noexcept
        : Ip((ui32(a) << 24) | (ui32(b) << 16) | (ui32(c) << 8) | ui32(d))
        , Type_(TIpv6Address::Ipv4)
    {}

    constexpr TIpv6Address(ui16 a, ui16 b, ui16 c, ui16 d, ui16 e, ui16 f, ui16 g, ui16 h, ui32 scope = 0) noexcept
        : Type_(TIpv6Address::Ipv6)
        , ScopeId_(scope)
    {
        auto hi = (ui64(a) << 48) | (ui64(b) << 32) | (ui64(c) << 16) | ui64(d);
        auto lo = (ui64(e) << 48) | (ui64(f) << 32) | (ui64(g) << 16) | ui64(h);
        Ip = {hi, lo};
    }

    explicit TIpv6Address(const NAddr::IRemoteAddr& addr);
    explicit TIpv6Address(const sockaddr_in6& Addr);
    explicit TIpv6Address(const sockaddr_in& Addr);
    explicit TIpv6Address(const in6_addr& addr, ui32 Scope);
    explicit TIpv6Address(const in_addr& addr);

    static TIpv6Address FromString(TStringBuf srcStr, bool& ok) noexcept;
    static TIpv6Address FromString(TStringBuf str) noexcept;

    constexpr bool IsNull() const noexcept {
        return Ip == 0;
    }

    constexpr bool IsValid() const noexcept {
        return Ip != 0 && (Type_ == Ipv6 || Type_ == Ipv4);
    }

    explicit constexpr operator bool() const noexcept {
        return IsValid();
    }

    constexpr bool operator ! () const noexcept {
        return !IsValid();
    }

    bool Isv4MappedTov6() const noexcept;
    TIpv6Address TryToExtractIpv4From6() const noexcept;
    TIpv6Address Normalized() const noexcept;

    TString ToString(bool* ok = nullptr) const noexcept;
    TString ToString(bool PrintScopeId, bool* ok = nullptr) const noexcept;

    void ToSockaddrAndSocklen(sockaddr_in& sockAddrIPv4,
                              sockaddr_in6& sockAddrIPv6, // in
                              const sockaddr*& sockAddrPtr,
                              socklen_t& sockAddrSize,
                              ui16 Port) const; // out

    void ToInAddr(in_addr& Addr4) const;
    void ToIn6Addr(in6_addr& Addr6) const;
    // int SocketFamily() const;

    constexpr bool operator<(const TIpv6Address& other) const noexcept {
        if (Type_ != other.Type_)
            return Type_ > other.Type_;
        else
            return Ip < other.Ip;
    }
    constexpr bool operator>(const TIpv6Address& other) const noexcept {
        if (Type_ != other.Type_)
            return Type_ < other.Type_;
        else
            return Ip > other.Ip;
    }
    constexpr bool operator==(const TIpv6Address& other) const noexcept {
        return Type_ == other.Type_ && Ip == other.Ip;
    }
    constexpr bool operator!=(const TIpv6Address& other) const noexcept {
        return Type_ != other.Type_ || Ip != other.Ip;
    }

    constexpr bool operator<=(const TIpv6Address& other) const noexcept {
        return !(*this > other);
    }

    constexpr bool operator>=(const TIpv6Address& other) const noexcept {
        return !(*this < other);
    }

    constexpr operator ui128() const noexcept {
        return Ip;
    }

    constexpr TIpType Type() const noexcept {
        return Type_;
    }

    void SetScopeId(ui32 New) noexcept {
        ScopeId_ = New;
    }
    constexpr ui32 ScopeId() const noexcept {
        return ScopeId_;
    }

    void Save(IOutputStream* out) const;
    void Load(IInputStream* in);

private:
    void InitFrom(const in6_addr& addr);
    void InitFrom(const in_addr& addr);

    void InitFrom(const sockaddr_in6& Addr);
    void InitFrom(const sockaddr_in& Addr);

    ui128 Ip{};
    TIpType Type_ = LAST;
    ui32 ScopeId_ = 0;
};
IOutputStream& operator<<(IOutputStream& Out, const TIpv6Address::TIpType Type) noexcept;
IOutputStream& operator<<(IOutputStream& Out, const TIpv6Address& ipv6Address) noexcept;

constexpr TIpv6Address Get127001() noexcept {
    return {127, 0, 0, 1};
}

constexpr TIpv6Address Get1() noexcept {
    return {1, TIpv6Address::Ipv6};
}

struct THostAddressAndPort {
    constexpr THostAddressAndPort() noexcept = default;
    constexpr THostAddressAndPort(const TIpv6Address& i, TIpPort p) noexcept {
        Ip = i;
        Port = p;
    }

    constexpr bool operator==(const THostAddressAndPort& Other) const noexcept {
        return Ip == Other.Ip && Port == Other.Port;
    }
    constexpr bool operator!=(const THostAddressAndPort& Other) const noexcept {
        return !(*this == Other);
    }
    constexpr bool IsValid() const noexcept {
        return Ip.IsValid() && Port != 0;
    }

    TString ToString() const noexcept;

    TIpv6Address Ip {};
    TIpPort Port {0};
};
IOutputStream& operator<<(IOutputStream& Out, const THostAddressAndPort& HostAddressAndPort) noexcept;

///
/// Returns
///   1. either valid THostAddressAndPort
///   2. or TString with hostname (which you should resolve) and TIpPort with port
///   3. or error, if Ok == false
///
/// Supported RawStrs are
///   1.2.3.4          // port wil be equal to DefaultPort
///   1.2.3.4:80
///   [2001::7348]     // port wil be equal to DefaultPort
///   2001::7348       // port wil be equal to DefaultPort
///   [2001::7348]:80
///
std::tuple<THostAddressAndPort, TString, TIpPort> ParseHostAndMayBePortFromString(const TString& RawStr,
                                                                                  TIpPort DefaultPort,
                                                                                  bool& Ok) noexcept;

using TIpv6AddressesSet = THashSet<TIpv6Address>;

template <>
struct THash<TIpv6Address> {
    inline size_t operator()(const TIpv6Address& ip) const {
        const ui128& Tmp = static_cast<ui128>(ip);
        return CombineHashes(THash<ui128>()(Tmp), THash<ui8>()(static_cast<ui8>(ip.Type())));
    }
};
template <>
struct THash<THostAddressAndPort> {
    inline size_t operator()(const THostAddressAndPort& IpAndPort) const {
        return CombineHashes(THash<TIpv6Address>()(IpAndPort.Ip), THash<TIpPort>()(IpAndPort.Port));
    }
};

namespace std {
    template <>
    struct hash<TIpv6Address> {
        std::size_t operator()(const TIpv6Address& Ip) const noexcept {
            return THash<TIpv6Address>()(Ip);
        }
    };
}

NAddr::IRemoteAddr* ToIRemoteAddr(const TIpv6Address& Address, TIpPort Port);

// template <>
// class TSerializer<TIpv6Address> {
// public:
//    static void Save(IOutputStream *out, const TIpv6Address &ip);
//    static void Load(IInputStream *in, TIpv6Address &ip);
//};