aboutsummaryrefslogtreecommitdiffstats
path: root/util/draft/ip.h
blob: 5a4ff7f46be3c60ef0d85afed34c63ffc906bd43 (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
#pragma once

#include <util/digest/murmur.h>

#include <util/network/ip.h>

#include <util/str_stl.h>
#include <util/generic/maybe.h>
#include <util/generic/variant.h>

#ifdef _unix_
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
#endif // _unix_

#include <string.h>

#ifndef INET6_ADDRSTRLEN
    #define INET6_ADDRSTRLEN 46
#endif

// Network (big-endian) byte order
using TIp4 = TIpHost;

// Network (big-endian) byte order
struct TIp6 {
    char Data[16];

    bool operator==(const TIp6& rhs) const {
        return memcmp(Data, rhs.Data, sizeof(Data)) == 0;
    }

    bool operator<(const TIp6& rhs) const {
        return memcmp(Data, rhs.Data, sizeof(Data)) < 0;
    }
};

template <>
struct THash<TIp6> {
    inline size_t operator()(const TIp6& ip) const {
        return MurmurHash<size_t>((const void*)ip.Data, 16);
    }
};

static inline TIp6 Ip6FromIp4(TIp4 addr) {
    TIp6 res;
    memset(res.Data, 0, sizeof(res.Data));
    res.Data[10] = '\xFF'; 
    res.Data[11] = '\xFF'; 
    memcpy(res.Data + 12, &addr, 4);
    return res;
}

static inline TIp6 Ip6FromString(const char* ipStr) {
    TIp6 res;

    if (inet_pton(AF_INET6, ipStr, &res.Data) == 0) {
        ythrow TSystemError() << "Failed to convert (" << ipStr << ") to ipv6 address";
    }

    return res;
}

static inline TMaybe<TIp6> TryParseIp6FromString(const char* ipStr) {
    TIp6 res;

    if (inet_pton(AF_INET6, ipStr, &res.Data) == 0) {
        return Nothing();
    }

    return res;
}

static inline char* Ip6ToString(const TIp6& ip, char* buf, size_t len) {
    if (!inet_ntop(AF_INET6, (void*)&ip.Data, buf, (socklen_t)len)) {
        ythrow TSystemError() << "Failed to get ipv6 address string";
    }

    return buf;
}

static inline TString Ip6ToString(const TIp6& ip) {
    char buf[INET6_ADDRSTRLEN];

    return TString(Ip6ToString(ip, buf, sizeof(buf)));
}

template <>
inline void Out<TIp6>(IOutputStream& os, const TIp6& a) {
    os << Ip6ToString(a);
}

using TIp4Or6 = std::variant<TIp4, TIp6>;

static inline TIp4Or6 Ip4Or6FromString(const char* ipStr) {
    const char* c = ipStr;
    for (; *c; ++c) {
        if (*c == '.') {
            return IpFromString(ipStr);
        }
        if (*c == ':') {
            return Ip6FromString(ipStr);
        }
    }
    ythrow TSystemError() << "Failed to convert (" << ipStr << ") to ipv4 or ipv6 address";
}

static inline TString Ip4Or6ToString(const TIp4Or6& ip) {
    if (std::holds_alternative<TIp6>(ip)) {
        return Ip6ToString(std::get<TIp6>(ip));
    } else {
        return IpToString(std::get<TIp4>(ip));
    }
}

// for TIp4 or TIp6, not TIp4Or6
template <class TIp>
struct TIpCompare {
    bool Less(const TIp& l, const TIp& r) const {
        return memcmp(&l, &r, sizeof(TIp)) < 0;
    }

    bool LessEqual(const TIp& l, const TIp& r) const {
        return memcmp(&l, &r, sizeof(TIp)) <= 0;
    }

    bool operator()(const TIp& l, const TIp& r) const {
        return Less(l, r);
    }
};