forked from nodejs/node
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcid.cc
151 lines (127 loc) · 4.01 KB
/
cid.cc
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
#if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
#include "cid.h"
#include <crypto/crypto_util.h>
#include <memory_tracker-inl.h>
#include <node_mutex.h>
#include <string_bytes.h>
#include "nbytes.h"
#include "ncrypto.h"
#include "quic/defs.h"
namespace node::quic {
// ============================================================================
// CID
CID::CID() : ptr_(&cid_) {
cid_.datalen = 0;
}
CID::CID(const ngtcp2_cid& cid) : CID(cid.data, cid.datalen) {}
CID::CID(const uint8_t* data, size_t len) : CID() {
DCHECK_LE(len, kMaxLength);
ngtcp2_cid_init(&cid_, data, len);
}
CID::CID(const ngtcp2_cid* cid) : ptr_(cid) {
CHECK_NOT_NULL(cid);
DCHECK_LE(cid->datalen, kMaxLength);
}
CID::CID(const CID& other) : ptr_(&cid_) {
CHECK_NOT_NULL(other.ptr_);
ngtcp2_cid_init(&cid_, other.ptr_->data, other.ptr_->datalen);
}
CID& CID::operator=(const CID& other) {
CHECK_NOT_NULL(other.ptr_);
ptr_ = &cid_;
ngtcp2_cid_init(&cid_, other.ptr_->data, other.ptr_->datalen);
return *this;
}
bool CID::operator==(const CID& other) const noexcept {
if (this == &other || (length() == 0 && other.length() == 0)) return true;
if (length() != other.length()) return false;
return memcmp(ptr_->data, other.ptr_->data, ptr_->datalen) == 0;
}
bool CID::operator!=(const CID& other) const noexcept {
return !(*this == other);
}
CID::operator const uint8_t*() const {
return ptr_->data;
}
CID::operator const ngtcp2_cid&() const {
return *ptr_;
}
CID::operator const ngtcp2_cid*() const {
return ptr_;
}
CID::operator bool() const {
return ptr_->datalen >= kMinLength;
}
size_t CID::length() const {
return ptr_->datalen;
}
std::string CID::ToString() const {
char dest[kMaxLength * 2];
size_t written = nbytes::HexEncode(reinterpret_cast<const char*>(ptr_->data),
ptr_->datalen,
dest,
arraysize(dest));
return std::string(dest, written);
}
CID CID::kInvalid{};
// ============================================================================
// CID::Hash
size_t CID::Hash::operator()(const CID& cid) const {
size_t hash = 0;
for (size_t n = 0; n < cid.length(); n++) {
hash ^= std::hash<uint8_t>{}(cid.ptr_->data[n] + 0x9e3779b9 + (hash << 6) +
(hash >> 2));
}
return hash;
}
// ============================================================================
// CID::Factory
namespace {
class RandomCIDFactory : public CID::Factory {
public:
RandomCIDFactory() = default;
DISALLOW_COPY_AND_MOVE(RandomCIDFactory)
CID Generate(size_t length_hint) const override {
DCHECK_GE(length_hint, CID::kMinLength);
DCHECK_LE(length_hint, CID::kMaxLength);
Mutex::ScopedLock lock(mutex_);
maybe_refresh_pool(length_hint);
auto start = pool_ + pos_;
pos_ += length_hint;
return CID(start, length_hint);
}
CID GenerateInto(ngtcp2_cid* cid,
size_t length_hint = CID::kMaxLength) const override {
DCHECK_GE(length_hint, CID::kMinLength);
DCHECK_LE(length_hint, CID::kMaxLength);
Mutex::ScopedLock lock(mutex_);
maybe_refresh_pool(length_hint);
auto start = pool_ + pos_;
pos_ += length_hint;
ngtcp2_cid_init(cid, start, length_hint);
return CID(cid);
}
private:
void maybe_refresh_pool(size_t length_hint) const {
// We generate a pool of random data kPoolSize in length
// and pull our random CID from that. If we don't have
// enough random random remaining in the pool to generate
// a CID of the requested size, we regenerate the pool
// and reset it to zero.
if (pos_ + length_hint > kPoolSize) {
CHECK(ncrypto::CSPRNG(pool_, kPoolSize));
pos_ = 0;
}
}
static constexpr int kPoolSize = 4096;
mutable int pos_ = kPoolSize;
mutable uint8_t pool_[kPoolSize];
mutable Mutex mutex_;
};
} // namespace
const CID::Factory& CID::Factory::random() {
static RandomCIDFactory instance;
return instance;
}
} // namespace node::quic
#endif // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC