librats 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/binding.gyp +1 -0
- package/lib/index.d.ts +2 -1
- package/native-src/3rdparty/android/ifaddrs-android.c +600 -0
- package/native-src/3rdparty/android/ifaddrs-android.h +54 -0
- package/native-src/CMakeLists.txt +360 -0
- package/native-src/LICENSE +21 -0
- package/native-src/src/bencode.cpp +485 -0
- package/native-src/src/bencode.h +145 -0
- package/native-src/src/bittorrent.cpp +3682 -0
- package/native-src/src/bittorrent.h +731 -0
- package/native-src/src/dht.cpp +2460 -0
- package/native-src/src/dht.h +508 -0
- package/native-src/src/encrypted_socket.cpp +817 -0
- package/native-src/src/encrypted_socket.h +239 -0
- package/native-src/src/file_transfer.cpp +1808 -0
- package/native-src/src/file_transfer.h +567 -0
- package/native-src/src/fs.cpp +639 -0
- package/native-src/src/fs.h +108 -0
- package/native-src/src/gossipsub.cpp +1137 -0
- package/native-src/src/gossipsub.h +403 -0
- package/native-src/src/ice.cpp +1386 -0
- package/native-src/src/ice.h +328 -0
- package/native-src/src/json.hpp +25526 -0
- package/native-src/src/krpc.cpp +558 -0
- package/native-src/src/krpc.h +145 -0
- package/native-src/src/librats.cpp +2735 -0
- package/native-src/src/librats.h +1732 -0
- package/native-src/src/librats_bittorrent.cpp +167 -0
- package/native-src/src/librats_c.cpp +1333 -0
- package/native-src/src/librats_c.h +239 -0
- package/native-src/src/librats_encryption.cpp +123 -0
- package/native-src/src/librats_file_transfer.cpp +226 -0
- package/native-src/src/librats_gossipsub.cpp +293 -0
- package/native-src/src/librats_ice.cpp +515 -0
- package/native-src/src/librats_logging.cpp +158 -0
- package/native-src/src/librats_mdns.cpp +171 -0
- package/native-src/src/librats_nat.cpp +571 -0
- package/native-src/src/librats_persistence.cpp +815 -0
- package/native-src/src/logger.h +412 -0
- package/native-src/src/mdns.cpp +1178 -0
- package/native-src/src/mdns.h +253 -0
- package/native-src/src/network_utils.cpp +598 -0
- package/native-src/src/network_utils.h +162 -0
- package/native-src/src/noise.cpp +981 -0
- package/native-src/src/noise.h +227 -0
- package/native-src/src/os.cpp +371 -0
- package/native-src/src/os.h +40 -0
- package/native-src/src/rats_export.h +17 -0
- package/native-src/src/sha1.cpp +163 -0
- package/native-src/src/sha1.h +42 -0
- package/native-src/src/socket.cpp +1376 -0
- package/native-src/src/socket.h +309 -0
- package/native-src/src/stun.cpp +484 -0
- package/native-src/src/stun.h +349 -0
- package/native-src/src/threadmanager.cpp +105 -0
- package/native-src/src/threadmanager.h +53 -0
- package/native-src/src/tracker.cpp +1110 -0
- package/native-src/src/tracker.h +268 -0
- package/native-src/src/version.cpp +24 -0
- package/native-src/src/version.h.in +45 -0
- package/native-src/version.rc.in +31 -0
- package/package.json +2 -8
- package/scripts/build-librats.js +59 -12
- package/scripts/prepare-package.js +133 -37
- package/src/librats_node.cpp +46 -1
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
#include "bencode.h"
|
|
2
|
+
#include <stdexcept>
|
|
3
|
+
#include <sstream>
|
|
4
|
+
#include <algorithm>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
|
|
7
|
+
namespace librats {
|
|
8
|
+
|
|
9
|
+
// BencodeValue implementation
|
|
10
|
+
BencodeValue::BencodeValue() : type_(Type::String), value_(std::string()) {}
|
|
11
|
+
|
|
12
|
+
BencodeValue::BencodeValue(int64_t value) : type_(Type::Integer), value_(value) {}
|
|
13
|
+
|
|
14
|
+
BencodeValue::BencodeValue(const std::string& value) : type_(Type::String), value_(value) {}
|
|
15
|
+
|
|
16
|
+
BencodeValue::BencodeValue(const char* value) : type_(Type::String), value_(std::string(value)) {}
|
|
17
|
+
|
|
18
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
19
|
+
BencodeValue::BencodeValue(const BencodeList& value) : type_(Type::List), value_(std::make_shared<BencodeList>(value)) {}
|
|
20
|
+
#else
|
|
21
|
+
BencodeValue::BencodeValue(const BencodeList& value) : type_(Type::List), value_(value) {}
|
|
22
|
+
#endif
|
|
23
|
+
|
|
24
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
25
|
+
BencodeValue::BencodeValue(const BencodeDict& value) : type_(Type::Dictionary), value_(std::make_shared<BencodeDict>(value)) {}
|
|
26
|
+
#else
|
|
27
|
+
BencodeValue::BencodeValue(const BencodeDict& value) : type_(Type::Dictionary), value_(value) {}
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
BencodeValue::BencodeValue(const BencodeValue& other) : type_(other.type_), value_(other.value_) {}
|
|
31
|
+
|
|
32
|
+
BencodeValue::BencodeValue(BencodeValue&& other) noexcept : type_(other.type_), value_(std::move(other.value_)) {}
|
|
33
|
+
|
|
34
|
+
BencodeValue& BencodeValue::operator=(const BencodeValue& other) {
|
|
35
|
+
if (this != &other) {
|
|
36
|
+
type_ = other.type_;
|
|
37
|
+
value_ = other.value_;
|
|
38
|
+
}
|
|
39
|
+
return *this;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
BencodeValue& BencodeValue::operator=(BencodeValue&& other) noexcept {
|
|
43
|
+
if (this != &other) {
|
|
44
|
+
type_ = other.type_;
|
|
45
|
+
value_ = std::move(other.value_);
|
|
46
|
+
}
|
|
47
|
+
return *this;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
BencodeValue::~BencodeValue() = default;
|
|
51
|
+
|
|
52
|
+
int64_t BencodeValue::as_integer() const {
|
|
53
|
+
if (type_ != Type::Integer) {
|
|
54
|
+
throw std::runtime_error("BencodeValue is not an integer");
|
|
55
|
+
}
|
|
56
|
+
return std::get<int64_t>(value_);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const std::string& BencodeValue::as_string() const {
|
|
60
|
+
if (type_ != Type::String) {
|
|
61
|
+
throw std::runtime_error("BencodeValue is not a string");
|
|
62
|
+
}
|
|
63
|
+
return std::get<std::string>(value_);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const BencodeList& BencodeValue::as_list() const {
|
|
67
|
+
if (type_ != Type::List) {
|
|
68
|
+
throw std::runtime_error("BencodeValue is not a list");
|
|
69
|
+
}
|
|
70
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
71
|
+
return *std::get<std::shared_ptr<BencodeList>>(value_);
|
|
72
|
+
#else
|
|
73
|
+
return std::get<BencodeList>(value_);
|
|
74
|
+
#endif
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const BencodeDict& BencodeValue::as_dict() const {
|
|
78
|
+
if (type_ != Type::Dictionary) {
|
|
79
|
+
throw std::runtime_error("BencodeValue is not a dictionary");
|
|
80
|
+
}
|
|
81
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
82
|
+
return *std::get<std::shared_ptr<BencodeDict>>(value_);
|
|
83
|
+
#else
|
|
84
|
+
return std::get<BencodeDict>(value_);
|
|
85
|
+
#endif
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
BencodeList& BencodeValue::as_list() {
|
|
89
|
+
if (type_ != Type::List) {
|
|
90
|
+
throw std::runtime_error("BencodeValue is not a list");
|
|
91
|
+
}
|
|
92
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
93
|
+
return *std::get<std::shared_ptr<BencodeList>>(value_);
|
|
94
|
+
#else
|
|
95
|
+
return std::get<BencodeList>(value_);
|
|
96
|
+
#endif
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
BencodeDict& BencodeValue::as_dict() {
|
|
100
|
+
if (type_ != Type::Dictionary) {
|
|
101
|
+
throw std::runtime_error("BencodeValue is not a dictionary");
|
|
102
|
+
}
|
|
103
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
104
|
+
return *std::get<std::shared_ptr<BencodeDict>>(value_);
|
|
105
|
+
#else
|
|
106
|
+
return std::get<BencodeDict>(value_);
|
|
107
|
+
#endif
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
bool BencodeValue::has_key(const std::string& key) const {
|
|
111
|
+
if (type_ != Type::Dictionary) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
115
|
+
const auto& dict = *std::get<std::shared_ptr<BencodeDict>>(value_);
|
|
116
|
+
#else
|
|
117
|
+
const auto& dict = std::get<BencodeDict>(value_);
|
|
118
|
+
#endif
|
|
119
|
+
return dict.find(key) != dict.end();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const BencodeValue& BencodeValue::operator[](const std::string& key) const {
|
|
123
|
+
if (type_ != Type::Dictionary) {
|
|
124
|
+
throw std::runtime_error("BencodeValue is not a dictionary");
|
|
125
|
+
}
|
|
126
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
127
|
+
const auto& dict = *std::get<std::shared_ptr<BencodeDict>>(value_);
|
|
128
|
+
#else
|
|
129
|
+
const auto& dict = std::get<BencodeDict>(value_);
|
|
130
|
+
#endif
|
|
131
|
+
auto it = dict.find(key);
|
|
132
|
+
if (it == dict.end()) {
|
|
133
|
+
throw std::runtime_error("Key not found in dictionary: " + key);
|
|
134
|
+
}
|
|
135
|
+
return it->second;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
BencodeValue& BencodeValue::operator[](const std::string& key) {
|
|
139
|
+
if (type_ != Type::Dictionary) {
|
|
140
|
+
throw std::runtime_error("BencodeValue is not a dictionary");
|
|
141
|
+
}
|
|
142
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
143
|
+
auto& dict = *std::get<std::shared_ptr<BencodeDict>>(value_);
|
|
144
|
+
#else
|
|
145
|
+
auto& dict = std::get<BencodeDict>(value_);
|
|
146
|
+
#endif
|
|
147
|
+
return dict[key];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const BencodeValue& BencodeValue::operator[](size_t index) const {
|
|
151
|
+
if (type_ != Type::List) {
|
|
152
|
+
throw std::runtime_error("BencodeValue is not a list");
|
|
153
|
+
}
|
|
154
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
155
|
+
const auto& list = *std::get<std::shared_ptr<BencodeList>>(value_);
|
|
156
|
+
#else
|
|
157
|
+
const auto& list = std::get<BencodeList>(value_);
|
|
158
|
+
#endif
|
|
159
|
+
if (index >= list.size()) {
|
|
160
|
+
throw std::runtime_error("Index out of bounds");
|
|
161
|
+
}
|
|
162
|
+
return list[index];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
BencodeValue& BencodeValue::operator[](size_t index) {
|
|
166
|
+
if (type_ != Type::List) {
|
|
167
|
+
throw std::runtime_error("BencodeValue is not a list");
|
|
168
|
+
}
|
|
169
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
170
|
+
auto& list = *std::get<std::shared_ptr<BencodeList>>(value_);
|
|
171
|
+
#else
|
|
172
|
+
auto& list = std::get<BencodeList>(value_);
|
|
173
|
+
#endif
|
|
174
|
+
if (index >= list.size()) {
|
|
175
|
+
throw std::runtime_error("Index out of bounds");
|
|
176
|
+
}
|
|
177
|
+
return list[index];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
void BencodeValue::push_back(const BencodeValue& value) {
|
|
181
|
+
if (type_ != Type::List) {
|
|
182
|
+
throw std::runtime_error("BencodeValue is not a list");
|
|
183
|
+
}
|
|
184
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
185
|
+
auto& list = *std::get<std::shared_ptr<BencodeList>>(value_);
|
|
186
|
+
#else
|
|
187
|
+
auto& list = std::get<BencodeList>(value_);
|
|
188
|
+
#endif
|
|
189
|
+
list.push_back(value);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
size_t BencodeValue::size() const {
|
|
193
|
+
switch (type_) {
|
|
194
|
+
case Type::String:
|
|
195
|
+
return std::get<std::string>(value_).size();
|
|
196
|
+
case Type::List:
|
|
197
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
198
|
+
return std::get<std::shared_ptr<BencodeList>>(value_)->size();
|
|
199
|
+
#else
|
|
200
|
+
return std::get<BencodeList>(value_).size();
|
|
201
|
+
#endif
|
|
202
|
+
case Type::Dictionary:
|
|
203
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
204
|
+
return std::get<std::shared_ptr<BencodeDict>>(value_)->size();
|
|
205
|
+
#else
|
|
206
|
+
return std::get<BencodeDict>(value_).size();
|
|
207
|
+
#endif
|
|
208
|
+
default:
|
|
209
|
+
throw std::runtime_error("Size not applicable to this type");
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
std::vector<uint8_t> BencodeValue::encode() const {
|
|
214
|
+
std::vector<uint8_t> buffer;
|
|
215
|
+
encode_to_buffer(buffer);
|
|
216
|
+
return buffer;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
std::string BencodeValue::encode_string() const {
|
|
220
|
+
auto buffer = encode();
|
|
221
|
+
return std::string(buffer.begin(), buffer.end());
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
void BencodeValue::encode_to_buffer(std::vector<uint8_t>& buffer) const {
|
|
225
|
+
switch (type_) {
|
|
226
|
+
case Type::Integer: {
|
|
227
|
+
std::string str = "i" + std::to_string(std::get<int64_t>(value_)) + "e";
|
|
228
|
+
buffer.insert(buffer.end(), str.begin(), str.end());
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
case Type::String: {
|
|
232
|
+
const auto& str = std::get<std::string>(value_);
|
|
233
|
+
std::string len_str = std::to_string(str.size()) + ":";
|
|
234
|
+
buffer.insert(buffer.end(), len_str.begin(), len_str.end());
|
|
235
|
+
buffer.insert(buffer.end(), str.begin(), str.end());
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
case Type::List: {
|
|
239
|
+
buffer.push_back('l');
|
|
240
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
241
|
+
const auto& list = *std::get<std::shared_ptr<BencodeList>>(value_);
|
|
242
|
+
#else
|
|
243
|
+
const auto& list = std::get<BencodeList>(value_);
|
|
244
|
+
#endif
|
|
245
|
+
for (const auto& item : list) {
|
|
246
|
+
item.encode_to_buffer(buffer);
|
|
247
|
+
}
|
|
248
|
+
buffer.push_back('e');
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
case Type::Dictionary: {
|
|
252
|
+
buffer.push_back('d');
|
|
253
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
254
|
+
const auto& dict = *std::get<std::shared_ptr<BencodeDict>>(value_);
|
|
255
|
+
#else
|
|
256
|
+
const auto& dict = std::get<BencodeDict>(value_);
|
|
257
|
+
#endif
|
|
258
|
+
|
|
259
|
+
// Sort keys for consistent encoding
|
|
260
|
+
std::vector<std::string> keys;
|
|
261
|
+
for (const auto& pair : dict) {
|
|
262
|
+
keys.push_back(pair.first);
|
|
263
|
+
}
|
|
264
|
+
std::sort(keys.begin(), keys.end());
|
|
265
|
+
|
|
266
|
+
for (const auto& key : keys) {
|
|
267
|
+
// Encode key
|
|
268
|
+
std::string len_str = std::to_string(key.size()) + ":";
|
|
269
|
+
buffer.insert(buffer.end(), len_str.begin(), len_str.end());
|
|
270
|
+
buffer.insert(buffer.end(), key.begin(), key.end());
|
|
271
|
+
|
|
272
|
+
// Encode value
|
|
273
|
+
dict.at(key).encode_to_buffer(buffer);
|
|
274
|
+
}
|
|
275
|
+
buffer.push_back('e');
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
BencodeValue BencodeValue::create_integer(int64_t value) {
|
|
282
|
+
return BencodeValue(value);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
BencodeValue BencodeValue::create_string(const std::string& value) {
|
|
286
|
+
return BencodeValue(value);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
BencodeValue BencodeValue::create_list() {
|
|
290
|
+
BencodeValue result;
|
|
291
|
+
result.type_ = Type::List;
|
|
292
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
293
|
+
result.value_ = std::make_shared<BencodeList>();
|
|
294
|
+
#else
|
|
295
|
+
result.value_ = BencodeList();
|
|
296
|
+
#endif
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
BencodeValue BencodeValue::create_dict() {
|
|
301
|
+
BencodeValue result;
|
|
302
|
+
result.type_ = Type::Dictionary;
|
|
303
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
304
|
+
result.value_ = std::make_shared<BencodeDict>();
|
|
305
|
+
#else
|
|
306
|
+
result.value_ = BencodeDict();
|
|
307
|
+
#endif
|
|
308
|
+
return result;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// BencodeDecoder implementation
|
|
312
|
+
BencodeDecoder::BencodeDecoder(const uint8_t* data, size_t size) : data_(data), size_(size), pos_(0) {}
|
|
313
|
+
|
|
314
|
+
BencodeValue BencodeDecoder::decode(const std::vector<uint8_t>& data) {
|
|
315
|
+
return decode(data.data(), data.size());
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
BencodeValue BencodeDecoder::decode(const std::string& data) {
|
|
319
|
+
return decode(reinterpret_cast<const uint8_t*>(data.data()), data.size());
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
BencodeValue BencodeDecoder::decode(const uint8_t* data, size_t size) {
|
|
323
|
+
BencodeDecoder decoder(data, size);
|
|
324
|
+
return decoder.decode_value();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
BencodeValue BencodeDecoder::decode_value() {
|
|
328
|
+
if (!has_more()) {
|
|
329
|
+
throw std::runtime_error("Unexpected end of data");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
uint8_t first_byte = current_byte();
|
|
333
|
+
|
|
334
|
+
if (first_byte == 'i') {
|
|
335
|
+
return decode_integer();
|
|
336
|
+
} else if (first_byte == 'l') {
|
|
337
|
+
return decode_list();
|
|
338
|
+
} else if (first_byte == 'd') {
|
|
339
|
+
return decode_dict();
|
|
340
|
+
} else if (first_byte >= '0' && first_byte <= '9') {
|
|
341
|
+
return decode_string();
|
|
342
|
+
} else {
|
|
343
|
+
throw std::runtime_error("Invalid bencode data");
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
BencodeValue BencodeDecoder::decode_integer() {
|
|
348
|
+
if (consume_byte() != 'i') {
|
|
349
|
+
throw std::runtime_error("Expected 'i' for integer");
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
std::string num_str;
|
|
353
|
+
while (has_more() && current_byte() != 'e') {
|
|
354
|
+
num_str += consume_byte();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (!has_more() || consume_byte() != 'e') {
|
|
358
|
+
throw std::runtime_error("Expected 'e' to end integer");
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (num_str.empty()) {
|
|
362
|
+
throw std::runtime_error("Empty integer");
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
try {
|
|
366
|
+
return BencodeValue(std::stoll(num_str));
|
|
367
|
+
} catch (const std::exception&) {
|
|
368
|
+
throw std::runtime_error("Invalid integer: " + num_str);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
BencodeValue BencodeDecoder::decode_string() {
|
|
373
|
+
std::string len_str;
|
|
374
|
+
while (has_more() && current_byte() != ':') {
|
|
375
|
+
len_str += consume_byte();
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (!has_more() || consume_byte() != ':') {
|
|
379
|
+
throw std::runtime_error("Expected ':' in string");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (len_str.empty()) {
|
|
383
|
+
throw std::runtime_error("Empty string length");
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
size_t length;
|
|
387
|
+
try {
|
|
388
|
+
length = std::stoull(len_str);
|
|
389
|
+
} catch (const std::exception&) {
|
|
390
|
+
throw std::runtime_error("Invalid string length: " + len_str);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (pos_ + length > size_) {
|
|
394
|
+
throw std::runtime_error("String length exceeds data size");
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
std::string str = consume_string(length);
|
|
398
|
+
return BencodeValue(str);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
BencodeValue BencodeDecoder::decode_list() {
|
|
402
|
+
if (consume_byte() != 'l') {
|
|
403
|
+
throw std::runtime_error("Expected 'l' for list");
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
BencodeValue list = BencodeValue::create_list();
|
|
407
|
+
|
|
408
|
+
while (has_more() && current_byte() != 'e') {
|
|
409
|
+
list.push_back(decode_value());
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (!has_more() || consume_byte() != 'e') {
|
|
413
|
+
throw std::runtime_error("Expected 'e' to end list");
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return list;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
BencodeValue BencodeDecoder::decode_dict() {
|
|
420
|
+
if (consume_byte() != 'd') {
|
|
421
|
+
throw std::runtime_error("Expected 'd' for dictionary");
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
BencodeValue dict = BencodeValue::create_dict();
|
|
425
|
+
|
|
426
|
+
while (has_more() && current_byte() != 'e') {
|
|
427
|
+
// Decode key (must be string)
|
|
428
|
+
BencodeValue key = decode_string();
|
|
429
|
+
|
|
430
|
+
// Decode value
|
|
431
|
+
BencodeValue value = decode_value();
|
|
432
|
+
|
|
433
|
+
dict[key.as_string()] = value;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (!has_more() || consume_byte() != 'e') {
|
|
437
|
+
throw std::runtime_error("Expected 'e' to end dictionary");
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return dict;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
uint8_t BencodeDecoder::current_byte() const {
|
|
444
|
+
if (pos_ >= size_) {
|
|
445
|
+
throw std::runtime_error("Unexpected end of data");
|
|
446
|
+
}
|
|
447
|
+
return data_[pos_];
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
uint8_t BencodeDecoder::consume_byte() {
|
|
451
|
+
if (pos_ >= size_) {
|
|
452
|
+
throw std::runtime_error("Unexpected end of data");
|
|
453
|
+
}
|
|
454
|
+
return data_[pos_++];
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
std::string BencodeDecoder::consume_string(size_t length) {
|
|
458
|
+
if (pos_ + length > size_) {
|
|
459
|
+
throw std::runtime_error("String length exceeds data size");
|
|
460
|
+
}
|
|
461
|
+
std::string str(reinterpret_cast<const char*>(data_ + pos_), length);
|
|
462
|
+
pos_ += length;
|
|
463
|
+
return str;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Utility functions
|
|
467
|
+
namespace bencode {
|
|
468
|
+
BencodeValue decode(const std::vector<uint8_t>& data) {
|
|
469
|
+
return BencodeDecoder::decode(data);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
BencodeValue decode(const std::string& data) {
|
|
473
|
+
return BencodeDecoder::decode(data);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
std::vector<uint8_t> encode(const BencodeValue& value) {
|
|
477
|
+
return value.encode();
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
std::string encode_string(const BencodeValue& value) {
|
|
481
|
+
return value.encode_string();
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
} // namespace librats
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <vector>
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <unordered_map>
|
|
6
|
+
#include <memory>
|
|
7
|
+
#include <variant>
|
|
8
|
+
#include <cstdint>
|
|
9
|
+
|
|
10
|
+
// Use shared_ptr variant for GCC 11 and lower compatibility
|
|
11
|
+
#ifndef LIBRATS_USE_SHARED_PTR_VARIANT
|
|
12
|
+
#if defined(__GNUC__) && (__GNUC__ <= 11)
|
|
13
|
+
#define LIBRATS_USE_SHARED_PTR_VARIANT 1
|
|
14
|
+
#else
|
|
15
|
+
#define LIBRATS_USE_SHARED_PTR_VARIANT 0
|
|
16
|
+
#endif
|
|
17
|
+
#endif
|
|
18
|
+
|
|
19
|
+
namespace librats {
|
|
20
|
+
|
|
21
|
+
// Forward declarations
|
|
22
|
+
class BencodeValue;
|
|
23
|
+
using BencodeDict = std::unordered_map<std::string, BencodeValue>;
|
|
24
|
+
using BencodeList = std::vector<BencodeValue>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Represents a bencoded value which can be:
|
|
28
|
+
* - Integer (signed 64-bit)
|
|
29
|
+
* - String (byte string)
|
|
30
|
+
* - List (array of bencoded values)
|
|
31
|
+
* - Dictionary (map of string keys to bencoded values)
|
|
32
|
+
*/
|
|
33
|
+
class BencodeValue {
|
|
34
|
+
public:
|
|
35
|
+
enum class Type {
|
|
36
|
+
Integer,
|
|
37
|
+
String,
|
|
38
|
+
List,
|
|
39
|
+
Dictionary
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Constructors
|
|
43
|
+
BencodeValue();
|
|
44
|
+
BencodeValue(int64_t value);
|
|
45
|
+
BencodeValue(const std::string& value);
|
|
46
|
+
BencodeValue(const char* value);
|
|
47
|
+
BencodeValue(const BencodeList& value);
|
|
48
|
+
BencodeValue(const BencodeDict& value);
|
|
49
|
+
|
|
50
|
+
// Copy and move constructors
|
|
51
|
+
BencodeValue(const BencodeValue& other);
|
|
52
|
+
BencodeValue(BencodeValue&& other) noexcept;
|
|
53
|
+
BencodeValue& operator=(const BencodeValue& other);
|
|
54
|
+
BencodeValue& operator=(BencodeValue&& other) noexcept;
|
|
55
|
+
|
|
56
|
+
~BencodeValue();
|
|
57
|
+
|
|
58
|
+
// Type checking
|
|
59
|
+
Type get_type() const { return type_; }
|
|
60
|
+
bool is_integer() const { return type_ == Type::Integer; }
|
|
61
|
+
bool is_string() const { return type_ == Type::String; }
|
|
62
|
+
bool is_list() const { return type_ == Type::List; }
|
|
63
|
+
bool is_dict() const { return type_ == Type::Dictionary; }
|
|
64
|
+
|
|
65
|
+
// Value access
|
|
66
|
+
int64_t as_integer() const;
|
|
67
|
+
const std::string& as_string() const;
|
|
68
|
+
const BencodeList& as_list() const;
|
|
69
|
+
const BencodeDict& as_dict() const;
|
|
70
|
+
|
|
71
|
+
// Mutable access
|
|
72
|
+
BencodeList& as_list();
|
|
73
|
+
BencodeDict& as_dict();
|
|
74
|
+
|
|
75
|
+
// Dictionary operations
|
|
76
|
+
bool has_key(const std::string& key) const;
|
|
77
|
+
const BencodeValue& operator[](const std::string& key) const;
|
|
78
|
+
BencodeValue& operator[](const std::string& key);
|
|
79
|
+
|
|
80
|
+
// List operations
|
|
81
|
+
const BencodeValue& operator[](size_t index) const;
|
|
82
|
+
BencodeValue& operator[](size_t index);
|
|
83
|
+
void push_back(const BencodeValue& value);
|
|
84
|
+
size_t size() const;
|
|
85
|
+
|
|
86
|
+
// Encoding
|
|
87
|
+
std::vector<uint8_t> encode() const;
|
|
88
|
+
std::string encode_string() const;
|
|
89
|
+
|
|
90
|
+
// Static creation methods
|
|
91
|
+
static BencodeValue create_integer(int64_t value);
|
|
92
|
+
static BencodeValue create_string(const std::string& value);
|
|
93
|
+
static BencodeValue create_list();
|
|
94
|
+
static BencodeValue create_dict();
|
|
95
|
+
|
|
96
|
+
private:
|
|
97
|
+
Type type_;
|
|
98
|
+
#if LIBRATS_USE_SHARED_PTR_VARIANT
|
|
99
|
+
std::variant<int64_t, std::string, std::shared_ptr<BencodeList>, std::shared_ptr<BencodeDict>> value_;
|
|
100
|
+
#else
|
|
101
|
+
std::variant<int64_t, std::string, BencodeList, BencodeDict> value_;
|
|
102
|
+
#endif
|
|
103
|
+
|
|
104
|
+
void encode_to_buffer(std::vector<uint8_t>& buffer) const;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Bencode decoder
|
|
109
|
+
*/
|
|
110
|
+
class BencodeDecoder {
|
|
111
|
+
public:
|
|
112
|
+
static BencodeValue decode(const std::vector<uint8_t>& data);
|
|
113
|
+
static BencodeValue decode(const std::string& data);
|
|
114
|
+
static BencodeValue decode(const uint8_t* data, size_t size);
|
|
115
|
+
|
|
116
|
+
private:
|
|
117
|
+
const uint8_t* data_;
|
|
118
|
+
size_t size_;
|
|
119
|
+
size_t pos_;
|
|
120
|
+
|
|
121
|
+
BencodeDecoder(const uint8_t* data, size_t size);
|
|
122
|
+
|
|
123
|
+
BencodeValue decode_value();
|
|
124
|
+
BencodeValue decode_integer();
|
|
125
|
+
BencodeValue decode_string();
|
|
126
|
+
BencodeValue decode_list();
|
|
127
|
+
BencodeValue decode_dict();
|
|
128
|
+
|
|
129
|
+
bool has_more() const { return pos_ < size_; }
|
|
130
|
+
uint8_t current_byte() const;
|
|
131
|
+
uint8_t consume_byte();
|
|
132
|
+
std::string consume_string(size_t length);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Utility functions
|
|
137
|
+
*/
|
|
138
|
+
namespace bencode {
|
|
139
|
+
BencodeValue decode(const std::vector<uint8_t>& data);
|
|
140
|
+
BencodeValue decode(const std::string& data);
|
|
141
|
+
std::vector<uint8_t> encode(const BencodeValue& value);
|
|
142
|
+
std::string encode_string(const BencodeValue& value);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
} // namespace librats
|