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,227 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <array>
|
|
4
|
+
#include <vector>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <memory>
|
|
7
|
+
#include <cstdint>
|
|
8
|
+
|
|
9
|
+
namespace librats {
|
|
10
|
+
|
|
11
|
+
// Noise Protocol constants
|
|
12
|
+
constexpr size_t NOISE_KEY_SIZE = 32; // 32 bytes for Curve25519 keys
|
|
13
|
+
constexpr size_t NOISE_HASH_SIZE = 32; // 32 bytes for SHA256
|
|
14
|
+
constexpr size_t NOISE_TAG_SIZE = 16; // 16 bytes for ChaCha20-Poly1305 tag
|
|
15
|
+
constexpr size_t NOISE_MAX_MESSAGE_SIZE = 65535; // Maximum noise message size
|
|
16
|
+
|
|
17
|
+
// Noise key types
|
|
18
|
+
using NoiseKey = std::array<uint8_t, NOISE_KEY_SIZE>;
|
|
19
|
+
using NoiseHash = std::array<uint8_t, NOISE_HASH_SIZE>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Noise Protocol handshake state enumeration
|
|
23
|
+
*/
|
|
24
|
+
enum class NoiseHandshakeState {
|
|
25
|
+
UNINITIALIZED,
|
|
26
|
+
WRITE_MESSAGE_1, // Initiator sends first message
|
|
27
|
+
READ_MESSAGE_1, // Responder receives first message
|
|
28
|
+
WRITE_MESSAGE_2, // Responder sends second message
|
|
29
|
+
READ_MESSAGE_2, // Initiator receives second message
|
|
30
|
+
WRITE_MESSAGE_3, // Initiator sends third message
|
|
31
|
+
READ_MESSAGE_3, // Responder receives third message
|
|
32
|
+
COMPLETED, // Handshake completed successfully
|
|
33
|
+
FAILED // Handshake failed
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Noise Protocol role enumeration
|
|
38
|
+
*/
|
|
39
|
+
enum class NoiseRole {
|
|
40
|
+
INITIATOR, // The peer that initiates the handshake
|
|
41
|
+
RESPONDER // The peer that responds to the handshake
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Cryptographic functions interface for Noise Protocol
|
|
46
|
+
*/
|
|
47
|
+
class NoiseCrypto {
|
|
48
|
+
public:
|
|
49
|
+
// ECDH operations using Curve25519
|
|
50
|
+
static NoiseKey generate_keypair(NoiseKey& private_key);
|
|
51
|
+
static NoiseKey dh(const NoiseKey& private_key, const NoiseKey& public_key);
|
|
52
|
+
|
|
53
|
+
// AEAD encryption/decryption using ChaCha20-Poly1305
|
|
54
|
+
static std::vector<uint8_t> encrypt(const NoiseKey& key, uint64_t nonce,
|
|
55
|
+
const std::vector<uint8_t>& plaintext,
|
|
56
|
+
const std::vector<uint8_t>& ad = {});
|
|
57
|
+
static std::vector<uint8_t> decrypt(const NoiseKey& key, uint64_t nonce,
|
|
58
|
+
const std::vector<uint8_t>& ciphertext,
|
|
59
|
+
const std::vector<uint8_t>& ad = {});
|
|
60
|
+
|
|
61
|
+
// Hash functions using SHA256
|
|
62
|
+
static NoiseHash hash(const std::vector<uint8_t>& data);
|
|
63
|
+
static void hkdf(const std::vector<uint8_t>& salt, const std::vector<uint8_t>& ikm,
|
|
64
|
+
const std::vector<uint8_t>& info, uint8_t* okm, size_t okm_len);
|
|
65
|
+
|
|
66
|
+
// Utility functions
|
|
67
|
+
static void secure_memzero(void* ptr, size_t size);
|
|
68
|
+
static void random_bytes(uint8_t* buffer, size_t size);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Noise Protocol cipher state for managing encryption/decryption
|
|
73
|
+
*/
|
|
74
|
+
class NoiseCipherState {
|
|
75
|
+
public:
|
|
76
|
+
NoiseCipherState();
|
|
77
|
+
~NoiseCipherState();
|
|
78
|
+
|
|
79
|
+
void initialize_key(const NoiseKey& key);
|
|
80
|
+
bool has_key() const { return has_key_; }
|
|
81
|
+
|
|
82
|
+
std::vector<uint8_t> encrypt_with_ad(const std::vector<uint8_t>& plaintext,
|
|
83
|
+
const std::vector<uint8_t>& ad = {});
|
|
84
|
+
std::vector<uint8_t> decrypt_with_ad(const std::vector<uint8_t>& ciphertext,
|
|
85
|
+
const std::vector<uint8_t>& ad = {});
|
|
86
|
+
|
|
87
|
+
void set_nonce(uint64_t nonce) { nonce_ = nonce; }
|
|
88
|
+
uint64_t get_nonce() const { return nonce_; }
|
|
89
|
+
|
|
90
|
+
private:
|
|
91
|
+
NoiseKey key_;
|
|
92
|
+
uint64_t nonce_;
|
|
93
|
+
bool has_key_;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Noise Protocol symmetric state for managing handshake state
|
|
98
|
+
*/
|
|
99
|
+
class NoiseSymmetricState {
|
|
100
|
+
public:
|
|
101
|
+
NoiseSymmetricState();
|
|
102
|
+
~NoiseSymmetricState();
|
|
103
|
+
|
|
104
|
+
void initialize(const std::string& protocol_name);
|
|
105
|
+
void mix_key(const std::vector<uint8_t>& input_key_material);
|
|
106
|
+
void mix_hash(const std::vector<uint8_t>& data);
|
|
107
|
+
void mix_key_and_hash(const std::vector<uint8_t>& input_key_material);
|
|
108
|
+
|
|
109
|
+
std::vector<uint8_t> encrypt_and_hash(const std::vector<uint8_t>& plaintext);
|
|
110
|
+
std::vector<uint8_t> decrypt_and_hash(const std::vector<uint8_t>& ciphertext);
|
|
111
|
+
|
|
112
|
+
std::pair<NoiseCipherState, NoiseCipherState> split();
|
|
113
|
+
|
|
114
|
+
const NoiseHash& get_handshake_hash() const { return h_; }
|
|
115
|
+
|
|
116
|
+
private:
|
|
117
|
+
NoiseCipherState cipher_state_;
|
|
118
|
+
NoiseKey ck_; // Chaining key
|
|
119
|
+
NoiseHash h_; // Handshake hash
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Noise Protocol handshake state for Noise_XX pattern
|
|
124
|
+
*/
|
|
125
|
+
class NoiseHandshake {
|
|
126
|
+
public:
|
|
127
|
+
NoiseHandshake();
|
|
128
|
+
~NoiseHandshake();
|
|
129
|
+
|
|
130
|
+
// Initialize for either initiator or responder role
|
|
131
|
+
bool initialize(NoiseRole role, const NoiseKey& static_private_key);
|
|
132
|
+
|
|
133
|
+
// Handshake message processing
|
|
134
|
+
std::vector<uint8_t> write_message(const std::vector<uint8_t>& payload = {});
|
|
135
|
+
std::vector<uint8_t> read_message(const std::vector<uint8_t>& message);
|
|
136
|
+
|
|
137
|
+
// State queries
|
|
138
|
+
NoiseHandshakeState get_state() const { return state_; }
|
|
139
|
+
NoiseRole get_role() const { return role_; }
|
|
140
|
+
bool is_completed() const { return state_ == NoiseHandshakeState::COMPLETED; }
|
|
141
|
+
bool has_failed() const { return state_ == NoiseHandshakeState::FAILED; }
|
|
142
|
+
|
|
143
|
+
// Get cipher states after handshake completion
|
|
144
|
+
std::pair<NoiseCipherState, NoiseCipherState> get_cipher_states();
|
|
145
|
+
|
|
146
|
+
// Get remote static public key (available after handshake)
|
|
147
|
+
const NoiseKey& get_remote_static_public_key() const { return rs_; }
|
|
148
|
+
|
|
149
|
+
private:
|
|
150
|
+
NoiseRole role_;
|
|
151
|
+
NoiseHandshakeState state_;
|
|
152
|
+
NoiseSymmetricState symmetric_state_;
|
|
153
|
+
|
|
154
|
+
// Local keys
|
|
155
|
+
NoiseKey s_; // Local static private key
|
|
156
|
+
NoiseKey e_; // Local ephemeral private key
|
|
157
|
+
|
|
158
|
+
// Remote keys
|
|
159
|
+
NoiseKey rs_; // Remote static public key
|
|
160
|
+
NoiseKey re_; // Remote ephemeral public key
|
|
161
|
+
|
|
162
|
+
void advance_state();
|
|
163
|
+
void fail_handshake();
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* High-level Noise Protocol session manager
|
|
168
|
+
*/
|
|
169
|
+
class NoiseSession {
|
|
170
|
+
public:
|
|
171
|
+
NoiseSession();
|
|
172
|
+
~NoiseSession();
|
|
173
|
+
|
|
174
|
+
// Initialize session for client (initiator) or server (responder)
|
|
175
|
+
bool initialize_as_initiator(const NoiseKey& static_private_key);
|
|
176
|
+
bool initialize_as_responder(const NoiseKey& static_private_key);
|
|
177
|
+
|
|
178
|
+
// Handshake operations
|
|
179
|
+
bool is_handshake_completed() const;
|
|
180
|
+
bool has_handshake_failed() const;
|
|
181
|
+
|
|
182
|
+
std::vector<uint8_t> create_handshake_message(const std::vector<uint8_t>& payload = {});
|
|
183
|
+
std::vector<uint8_t> process_handshake_message(const std::vector<uint8_t>& message);
|
|
184
|
+
|
|
185
|
+
// Transport operations (available after handshake completion)
|
|
186
|
+
std::vector<uint8_t> encrypt_transport_message(const std::vector<uint8_t>& plaintext);
|
|
187
|
+
std::vector<uint8_t> decrypt_transport_message(const std::vector<uint8_t>& ciphertext);
|
|
188
|
+
|
|
189
|
+
// Utility functions
|
|
190
|
+
NoiseRole get_role() const;
|
|
191
|
+
NoiseHandshakeState get_handshake_state() const;
|
|
192
|
+
const NoiseKey& get_remote_static_public_key() const;
|
|
193
|
+
|
|
194
|
+
private:
|
|
195
|
+
std::unique_ptr<NoiseHandshake> handshake_state_;
|
|
196
|
+
std::unique_ptr<NoiseCipherState> send_cipher_;
|
|
197
|
+
std::unique_ptr<NoiseCipherState> receive_cipher_;
|
|
198
|
+
bool handshake_completed_;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Utility functions for Noise Protocol
|
|
203
|
+
*/
|
|
204
|
+
namespace noise_utils {
|
|
205
|
+
// Key management
|
|
206
|
+
NoiseKey generate_static_keypair();
|
|
207
|
+
std::string key_to_hex(const NoiseKey& key);
|
|
208
|
+
NoiseKey hex_to_key(const std::string& hex);
|
|
209
|
+
|
|
210
|
+
// Protocol utilities
|
|
211
|
+
std::string get_protocol_name();
|
|
212
|
+
bool validate_message_size(size_t size);
|
|
213
|
+
|
|
214
|
+
// Error handling
|
|
215
|
+
enum class NoiseError {
|
|
216
|
+
SUCCESS,
|
|
217
|
+
INVALID_STATE,
|
|
218
|
+
HANDSHAKE_FAILED,
|
|
219
|
+
DECRYPTION_FAILED,
|
|
220
|
+
INVALID_MESSAGE_SIZE,
|
|
221
|
+
CRYPTO_ERROR
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
std::string noise_error_to_string(NoiseError error);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
} // namespace librats
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
#include "os.h"
|
|
2
|
+
#include "logger.h"
|
|
3
|
+
#include <iostream>
|
|
4
|
+
#include <sstream>
|
|
5
|
+
#include <fstream>
|
|
6
|
+
#include <thread>
|
|
7
|
+
#include <cstdlib>
|
|
8
|
+
|
|
9
|
+
#ifdef _WIN32
|
|
10
|
+
#include <windows.h>
|
|
11
|
+
#include <sysinfoapi.h>
|
|
12
|
+
#include <versionhelpers.h>
|
|
13
|
+
#include <intrin.h>
|
|
14
|
+
#pragma comment(lib, "version.lib")
|
|
15
|
+
#elif __APPLE__
|
|
16
|
+
#include <sys/utsname.h>
|
|
17
|
+
#include <sys/sysctl.h>
|
|
18
|
+
#include <unistd.h>
|
|
19
|
+
#include <mach/mach.h>
|
|
20
|
+
#include <mach/vm_statistics.h>
|
|
21
|
+
#include <mach/mach_types.h>
|
|
22
|
+
#include <mach/mach_init.h>
|
|
23
|
+
#include <mach/mach_host.h>
|
|
24
|
+
#else
|
|
25
|
+
#include <sys/utsname.h>
|
|
26
|
+
#include <sys/sysinfo.h>
|
|
27
|
+
#include <unistd.h>
|
|
28
|
+
#include <fstream>
|
|
29
|
+
#include <regex>
|
|
30
|
+
#endif
|
|
31
|
+
|
|
32
|
+
namespace librats {
|
|
33
|
+
|
|
34
|
+
#ifdef _WIN32
|
|
35
|
+
|
|
36
|
+
std::string get_os_name() {
|
|
37
|
+
return "Windows";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
std::string get_os_version() {
|
|
41
|
+
std::string version = "Unknown";
|
|
42
|
+
|
|
43
|
+
OSVERSIONINFOEX osvi;
|
|
44
|
+
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
|
|
45
|
+
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
46
|
+
|
|
47
|
+
if (GetVersionEx((OSVERSIONINFO*)&osvi)) {
|
|
48
|
+
std::ostringstream oss;
|
|
49
|
+
oss << osvi.dwMajorVersion << "." << osvi.dwMinorVersion;
|
|
50
|
+
if (osvi.dwBuildNumber > 0) {
|
|
51
|
+
oss << "." << osvi.dwBuildNumber;
|
|
52
|
+
}
|
|
53
|
+
version = oss.str();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return version;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
std::string get_architecture() {
|
|
60
|
+
SYSTEM_INFO si;
|
|
61
|
+
GetSystemInfo(&si);
|
|
62
|
+
|
|
63
|
+
switch (si.wProcessorArchitecture) {
|
|
64
|
+
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
65
|
+
return "x64";
|
|
66
|
+
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
67
|
+
return "x86";
|
|
68
|
+
case PROCESSOR_ARCHITECTURE_ARM:
|
|
69
|
+
return "ARM";
|
|
70
|
+
case PROCESSOR_ARCHITECTURE_ARM64:
|
|
71
|
+
return "ARM64";
|
|
72
|
+
default:
|
|
73
|
+
return "Unknown";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
std::string get_hostname() {
|
|
78
|
+
char hostname[256];
|
|
79
|
+
DWORD hostname_len = sizeof(hostname);
|
|
80
|
+
if (GetComputerNameA(hostname, &hostname_len)) {
|
|
81
|
+
return std::string(hostname);
|
|
82
|
+
}
|
|
83
|
+
return "Unknown";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
std::string get_cpu_model() {
|
|
87
|
+
int CPUInfo[4] = {-1};
|
|
88
|
+
unsigned nExIds, i = 0;
|
|
89
|
+
char CPUBrandString[0x40];
|
|
90
|
+
|
|
91
|
+
__cpuid(CPUInfo, 0x80000000);
|
|
92
|
+
nExIds = CPUInfo[0];
|
|
93
|
+
|
|
94
|
+
for (i = 0x80000000; i <= nExIds; ++i) {
|
|
95
|
+
__cpuid(CPUInfo, i);
|
|
96
|
+
|
|
97
|
+
if (i == 0x80000002)
|
|
98
|
+
memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
|
|
99
|
+
else if (i == 0x80000003)
|
|
100
|
+
memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
|
|
101
|
+
else if (i == 0x80000004)
|
|
102
|
+
memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return std::string(CPUBrandString);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
int get_cpu_cores() {
|
|
109
|
+
SYSTEM_INFO si;
|
|
110
|
+
GetSystemInfo(&si);
|
|
111
|
+
return static_cast<int>(si.dwNumberOfProcessors);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
int get_cpu_logical_cores() {
|
|
115
|
+
return get_cpu_cores(); // Same as cores on Windows with this method
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
uint64_t get_total_memory_mb() {
|
|
119
|
+
MEMORYSTATUSEX memInfo;
|
|
120
|
+
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
|
|
121
|
+
GlobalMemoryStatusEx(&memInfo);
|
|
122
|
+
return memInfo.ullTotalPhys / (1024 * 1024);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
uint64_t get_available_memory_mb() {
|
|
126
|
+
MEMORYSTATUSEX memInfo;
|
|
127
|
+
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
|
|
128
|
+
GlobalMemoryStatusEx(&memInfo);
|
|
129
|
+
return memInfo.ullAvailPhys / (1024 * 1024);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
#elif __APPLE__
|
|
133
|
+
|
|
134
|
+
std::string get_os_name() {
|
|
135
|
+
return "macOS";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
std::string get_os_version() {
|
|
139
|
+
struct utsname unameData;
|
|
140
|
+
uname(&unameData);
|
|
141
|
+
return std::string(unameData.release);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
std::string get_architecture() {
|
|
145
|
+
struct utsname unameData;
|
|
146
|
+
uname(&unameData);
|
|
147
|
+
return std::string(unameData.machine);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
std::string get_hostname() {
|
|
151
|
+
struct utsname unameData;
|
|
152
|
+
uname(&unameData);
|
|
153
|
+
return std::string(unameData.nodename);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
std::string get_cpu_model() {
|
|
157
|
+
char buffer[256];
|
|
158
|
+
size_t size = sizeof(buffer);
|
|
159
|
+
if (sysctlbyname("machdep.cpu.brand_string", buffer, &size, NULL, 0) == 0) {
|
|
160
|
+
return std::string(buffer);
|
|
161
|
+
}
|
|
162
|
+
return "Unknown";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
int get_cpu_cores() {
|
|
166
|
+
int cores = 0;
|
|
167
|
+
size_t size = sizeof(cores);
|
|
168
|
+
if (sysctlbyname("hw.physicalcpu", &cores, &size, NULL, 0) == 0) {
|
|
169
|
+
return cores;
|
|
170
|
+
}
|
|
171
|
+
return std::thread::hardware_concurrency();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
int get_cpu_logical_cores() {
|
|
175
|
+
int cores = 0;
|
|
176
|
+
size_t size = sizeof(cores);
|
|
177
|
+
if (sysctlbyname("hw.logicalcpu", &cores, &size, NULL, 0) == 0) {
|
|
178
|
+
return cores;
|
|
179
|
+
}
|
|
180
|
+
return std::thread::hardware_concurrency();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
uint64_t get_total_memory_mb() {
|
|
184
|
+
uint64_t memsize = 0;
|
|
185
|
+
size_t size = sizeof(memsize);
|
|
186
|
+
if (sysctlbyname("hw.memsize", &memsize, &size, NULL, 0) == 0) {
|
|
187
|
+
return memsize / (1024 * 1024);
|
|
188
|
+
}
|
|
189
|
+
return 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
uint64_t get_available_memory_mb() {
|
|
193
|
+
vm_size_t page_size;
|
|
194
|
+
mach_port_t mach_port = mach_host_self();
|
|
195
|
+
vm_statistics64_data_t vm_stat;
|
|
196
|
+
mach_msg_type_number_t host_size = sizeof(vm_statistics64_data_t) / sizeof(natural_t);
|
|
197
|
+
|
|
198
|
+
host_page_size(mach_port, &page_size);
|
|
199
|
+
host_statistics64(mach_port, HOST_VM_INFO, (host_info64_t)&vm_stat, &host_size);
|
|
200
|
+
|
|
201
|
+
uint64_t free_memory = (uint64_t)vm_stat.free_count * (uint64_t)page_size;
|
|
202
|
+
return free_memory / (1024 * 1024);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
#else // Linux
|
|
206
|
+
|
|
207
|
+
std::string get_os_name() {
|
|
208
|
+
std::ifstream file("/etc/os-release");
|
|
209
|
+
std::string line;
|
|
210
|
+
while (std::getline(file, line)) {
|
|
211
|
+
if (line.find("PRETTY_NAME=") == 0) {
|
|
212
|
+
std::string name = line.substr(12);
|
|
213
|
+
// Remove quotes if present
|
|
214
|
+
if (name.front() == '"' && name.back() == '"') {
|
|
215
|
+
name = name.substr(1, name.length() - 2);
|
|
216
|
+
}
|
|
217
|
+
return name;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
struct utsname unameData;
|
|
222
|
+
uname(&unameData);
|
|
223
|
+
return std::string(unameData.sysname);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
std::string get_os_version() {
|
|
227
|
+
struct utsname unameData;
|
|
228
|
+
uname(&unameData);
|
|
229
|
+
return std::string(unameData.release);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
std::string get_architecture() {
|
|
233
|
+
struct utsname unameData;
|
|
234
|
+
uname(&unameData);
|
|
235
|
+
return std::string(unameData.machine);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
std::string get_hostname() {
|
|
239
|
+
struct utsname unameData;
|
|
240
|
+
uname(&unameData);
|
|
241
|
+
return std::string(unameData.nodename);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
std::string get_cpu_model() {
|
|
245
|
+
std::ifstream file("/proc/cpuinfo");
|
|
246
|
+
std::string line;
|
|
247
|
+
while (std::getline(file, line)) {
|
|
248
|
+
if (line.find("model name") != std::string::npos) {
|
|
249
|
+
size_t pos = line.find(':');
|
|
250
|
+
if (pos != std::string::npos) {
|
|
251
|
+
std::string model = line.substr(pos + 1);
|
|
252
|
+
// Trim whitespace
|
|
253
|
+
model.erase(0, model.find_first_not_of(" \t"));
|
|
254
|
+
model.erase(model.find_last_not_of(" \t") + 1);
|
|
255
|
+
return model;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return "Unknown";
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
int get_cpu_cores() {
|
|
263
|
+
std::ifstream file("/proc/cpuinfo");
|
|
264
|
+
std::string line;
|
|
265
|
+
int cores = 0;
|
|
266
|
+
|
|
267
|
+
while (std::getline(file, line)) {
|
|
268
|
+
if (line.find("cpu cores") != std::string::npos) {
|
|
269
|
+
size_t pos = line.find(':');
|
|
270
|
+
if (pos != std::string::npos) {
|
|
271
|
+
cores = std::stoi(line.substr(pos + 1));
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (cores == 0) {
|
|
278
|
+
cores = std::thread::hardware_concurrency();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return cores;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
int get_cpu_logical_cores() {
|
|
285
|
+
return std::thread::hardware_concurrency();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
uint64_t get_total_memory_mb() {
|
|
289
|
+
std::ifstream file("/proc/meminfo");
|
|
290
|
+
std::string line;
|
|
291
|
+
while (std::getline(file, line)) {
|
|
292
|
+
if (line.find("MemTotal:") == 0) {
|
|
293
|
+
std::regex regex(R"(MemTotal:\s+(\d+)\s+kB)");
|
|
294
|
+
std::smatch match;
|
|
295
|
+
if (std::regex_search(line, match, regex)) {
|
|
296
|
+
return std::stoull(match[1]) / 1024; // Convert kB to MB
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return 0;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
uint64_t get_available_memory_mb() {
|
|
304
|
+
std::ifstream file("/proc/meminfo");
|
|
305
|
+
std::string line;
|
|
306
|
+
while (std::getline(file, line)) {
|
|
307
|
+
if (line.find("MemAvailable:") == 0) {
|
|
308
|
+
std::regex regex(R"(MemAvailable:\s+(\d+)\s+kB)");
|
|
309
|
+
std::smatch match;
|
|
310
|
+
if (std::regex_search(line, match, regex)) {
|
|
311
|
+
return std::stoull(match[1]) / 1024; // Convert kB to MB
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return 0;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
#endif
|
|
319
|
+
|
|
320
|
+
SystemInfo get_system_info() {
|
|
321
|
+
SystemInfo info;
|
|
322
|
+
info.os_name = get_os_name();
|
|
323
|
+
info.os_version = get_os_version();
|
|
324
|
+
info.architecture = get_architecture();
|
|
325
|
+
info.hostname = get_hostname();
|
|
326
|
+
info.cpu_model = get_cpu_model();
|
|
327
|
+
info.cpu_cores = get_cpu_cores();
|
|
328
|
+
info.cpu_logical_cores = get_cpu_logical_cores();
|
|
329
|
+
info.total_memory_mb = get_total_memory_mb();
|
|
330
|
+
info.available_memory_mb = get_available_memory_mb();
|
|
331
|
+
return info;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
void print_system_info() {
|
|
335
|
+
SystemInfo info = get_system_info();
|
|
336
|
+
|
|
337
|
+
std::cout << "=== System Information ===" << std::endl;
|
|
338
|
+
std::cout << "OS: " << info.os_name << " " << info.os_version << std::endl;
|
|
339
|
+
std::cout << "Architecture: " << info.architecture << std::endl;
|
|
340
|
+
std::cout << "Hostname: " << info.hostname << std::endl;
|
|
341
|
+
std::cout << "CPU: " << info.cpu_model << std::endl;
|
|
342
|
+
std::cout << "CPU Cores: " << info.cpu_cores << " physical, " << info.cpu_logical_cores << " logical" << std::endl;
|
|
343
|
+
std::cout << "Memory: " << info.total_memory_mb << " MB total, " << info.available_memory_mb << " MB available" << std::endl;
|
|
344
|
+
std::cout << "=========================" << std::endl;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
bool supports_unicode() {
|
|
348
|
+
static bool checked = false;
|
|
349
|
+
static bool unicode_supported = false;
|
|
350
|
+
|
|
351
|
+
if (!checked) {
|
|
352
|
+
std::string os = get_os_name();
|
|
353
|
+
// Check if we're on Windows, which often has console encoding issues
|
|
354
|
+
if (os.find("Windows") != std::string::npos) {
|
|
355
|
+
// Try to detect if we're in a proper Unicode-enabled terminal
|
|
356
|
+
// For simplicity, we'll assume Windows console doesn't support Unicode well
|
|
357
|
+
// unless specific environment variables are set
|
|
358
|
+
const char* term = std::getenv("TERM");
|
|
359
|
+
const char* wt = std::getenv("WT_SESSION"); // Windows Terminal
|
|
360
|
+
unicode_supported = (term && std::string(term) != "dumb") || wt;
|
|
361
|
+
} else {
|
|
362
|
+
// On Unix-like systems, assume Unicode is supported
|
|
363
|
+
unicode_supported = true;
|
|
364
|
+
}
|
|
365
|
+
checked = true;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return unicode_supported;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
} // namespace librats
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
|
|
6
|
+
namespace librats {
|
|
7
|
+
|
|
8
|
+
struct SystemInfo {
|
|
9
|
+
std::string os_name;
|
|
10
|
+
std::string os_version;
|
|
11
|
+
std::string architecture;
|
|
12
|
+
std::string hostname;
|
|
13
|
+
std::string cpu_model;
|
|
14
|
+
int cpu_cores;
|
|
15
|
+
int cpu_logical_cores;
|
|
16
|
+
uint64_t total_memory_mb;
|
|
17
|
+
uint64_t available_memory_mb;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Get comprehensive system information
|
|
21
|
+
SystemInfo get_system_info();
|
|
22
|
+
|
|
23
|
+
// Individual functions for specific info
|
|
24
|
+
std::string get_os_name();
|
|
25
|
+
std::string get_os_version();
|
|
26
|
+
std::string get_architecture();
|
|
27
|
+
std::string get_hostname();
|
|
28
|
+
std::string get_cpu_model();
|
|
29
|
+
int get_cpu_cores();
|
|
30
|
+
int get_cpu_logical_cores();
|
|
31
|
+
uint64_t get_total_memory_mb();
|
|
32
|
+
uint64_t get_available_memory_mb();
|
|
33
|
+
|
|
34
|
+
// Unicode support detection
|
|
35
|
+
bool supports_unicode();
|
|
36
|
+
|
|
37
|
+
// Utility function to print system info
|
|
38
|
+
void print_system_info();
|
|
39
|
+
|
|
40
|
+
} // namespace librats
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#ifdef _WIN32
|
|
4
|
+
#if defined(RATS_EXPORT_DLL)
|
|
5
|
+
#define RATS_API __declspec(dllexport)
|
|
6
|
+
#elif defined(RATS_IMPORT_DLL)
|
|
7
|
+
#define RATS_API __declspec(dllimport)
|
|
8
|
+
#else
|
|
9
|
+
#define RATS_API
|
|
10
|
+
#endif
|
|
11
|
+
#else
|
|
12
|
+
#if __GNUC__ >= 4
|
|
13
|
+
#define RATS_API __attribute__((visibility("default")))
|
|
14
|
+
#else
|
|
15
|
+
#define RATS_API
|
|
16
|
+
#endif
|
|
17
|
+
#endif
|