Skip to content

Commit ebd1b4d

Browse files
release: cut v0.1.2 with discovery compatibility fixes
1 parent 2ea71a8 commit ebd1b4d

5 files changed

Lines changed: 76 additions & 17 deletions

dist/SHA256SUMS

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
82e9cc3b189657f2e8039a2881ce1761d0bdede6a65bae0327ee96e302f9cf4d dist/virtual_remote_server
2-
2845bd1d766786d080481c8a0fa979fb49cc575dd549dcbcbde99533770e3d9e dist/virtual_remote_server-linux-x86_64-v0.1.1.tar.gz
1+
3e70fd1a01964055a8613c36a4e7092ff337d96e10d1d4b43e212c0a4c7efcca dist/virtual_remote_server
2+
ae2d05133cc788c59be920aed32bf83a62e3f2c43cdc2393ba22cf2725754de5 dist/virtual_remote_server-linux-x86_64-v0.1.2.tar.gz

dist/virtual_remote_server

7.36 KB
Binary file not shown.
-33.2 KB
Binary file not shown.
37 KB
Binary file not shown.

src/discovery_service.cpp

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <unistd.h>
99

1010
#include <algorithm>
11+
#include <cctype>
1112
#include <chrono>
1213
#include <cstring>
1314
#include <fstream>
@@ -40,7 +41,9 @@ static uint64_t stableServerId() {
4041
std::getline(f, id);
4142

4243
// Remove whitespace/newlines just in case
43-
id.erase(std::remove_if(id.begin(), id.end(), ::isspace), id.end());
44+
id.erase(std::remove_if(id.begin(), id.end(),
45+
[](unsigned char c) { return std::isspace(c) != 0; }),
46+
id.end());
4447

4548
if (!id.empty()) {
4649
cached = fnv1a64(reinterpret_cast<const uint8_t*>(id.data()), id.size());
@@ -54,6 +57,30 @@ static uint64_t stableServerId() {
5457
return cached;
5558
}
5659

60+
static uint64_t bswap64_u(uint64_t v) {
61+
return ((v & 0x00000000000000FFull) << 56) |
62+
((v & 0x000000000000FF00ull) << 40) |
63+
((v & 0x0000000000FF0000ull) << 24) |
64+
((v & 0x00000000FF000000ull) << 8) |
65+
((v & 0x000000FF00000000ull) >> 8) |
66+
((v & 0x0000FF0000000000ull) >> 24) |
67+
((v & 0x00FF000000000000ull) >> 40) |
68+
((v & 0xFF00000000000000ull) >> 56);
69+
}
70+
71+
static uint64_t htonll_u(uint64_t v) {
72+
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
73+
return bswap64_u(v);
74+
#else
75+
return v;
76+
#endif
77+
}
78+
79+
static std::string makeLegacyReply(const ServerStatus& st) {
80+
return "CONTROLLER_AVAILABLE;udp=" + std::to_string(st.control_port) +
81+
";tcp=" + std::to_string(st.feedback_port);
82+
}
83+
5784
// -------------------- DiscoveryService --------------------
5885

5986
DiscoveryService::DiscoveryService(uint16_t port, StatusFn status_fn)
@@ -113,6 +140,8 @@ void DiscoveryService::stop() {
113140

114141
void DiscoveryService::runLoop() {
115142
std::vector<uint8_t> buf(1024);
143+
constexpr char kLegacyQuery[] = "WHO_IS_CONTROLLER";
144+
constexpr size_t kLegacyQueryLen = sizeof(kLegacyQuery) - 1;
116145

117146
// Simple per-IP rate limit: respond at most once per 150ms per source IP
118147
using Clock = std::chrono::steady_clock;
@@ -131,28 +160,46 @@ void DiscoveryService::runLoop() {
131160
continue;
132161
}
133162

134-
// Strict minimum size check
135-
if ((size_t)n < sizeof(DiscoverReqV1)) continue;
136-
137-
DiscoverReqV1 req{};
138-
std::memcpy(&req, buf.data(), sizeof(req));
139-
140-
// Validate request
141-
if (req.magic != kDiscoveryMagic) continue;
142-
if (req.version != kDiscoveryVersion) continue;
143-
if (req.msg_type != (uint8_t)DiscMsgType::DiscoverReq) continue;
144-
145163
// Rate limit by source IPv4
146164
uint32_t ipKey = src.sin_addr.s_addr; // network order is fine as a key
147165
auto now = Clock::now();
148166
auto it = lastReply.find(ipKey);
149167
if (it != lastReply.end() && (now - it->second) < minInterval) {
150168
continue;
151169
}
152-
lastReply[ipKey] = now;
153170

154171
// Build response from status provider
155172
ServerStatus st = status_fn_ ? status_fn_() : ServerStatus{};
173+
lastReply[ipKey] = now;
174+
175+
// Backward compatibility: old text-based discovery request.
176+
if ((size_t)n == kLegacyQueryLen &&
177+
std::memcmp(buf.data(), kLegacyQuery, kLegacyQueryLen) == 0) {
178+
const std::string reply = makeLegacyReply(st);
179+
::sendto(sock_, reply.data(), reply.size(), 0, (sockaddr*)&src, sizeof(src));
180+
continue;
181+
}
182+
183+
// Strict minimum size check for binary discovery request.
184+
if ((size_t)n < sizeof(DiscoverReqV1)) continue;
185+
186+
DiscoverReqV1 req{};
187+
std::memcpy(&req, buf.data(), sizeof(req));
188+
189+
// Accept both host-order (legacy implementation behavior) and network-order
190+
// client packets to avoid silent interoperability failures.
191+
bool request_network_order = false;
192+
uint32_t req_nonce = req.nonce;
193+
if (req.magic == kDiscoveryMagic) {
194+
request_network_order = false;
195+
} else if (ntohl(req.magic) == kDiscoveryMagic) {
196+
request_network_order = true;
197+
req_nonce = ntohl(req.nonce);
198+
} else {
199+
continue;
200+
}
201+
if (req.version != kDiscoveryVersion) continue;
202+
if (req.msg_type != (uint8_t)DiscMsgType::DiscoverReq) continue;
156203

157204
// Stable ID unless caller explicitly overrides
158205
if (st.server_id == 0) st.server_id = stableServerId();
@@ -170,14 +217,26 @@ void DiscoveryService::runLoop() {
170217
resp.version = kDiscoveryVersion;
171218
resp.msg_type = (uint8_t)DiscMsgType::DiscoverResp;
172219
resp.reserved = 0;
173-
resp.nonce = req.nonce;
220+
resp.nonce = req_nonce;
174221
resp.server_id = st.server_id;
175222
resp.control_port = st.control_port;
176223
resp.feedback_port = st.feedback_port;
177224
resp.proto_ver = st.controller_proto_ver;
178225
resp.name_len = (uint16_t)name.size();
179226
resp.flags = flags;
180227

228+
if (request_network_order) {
229+
resp.magic = htonl(resp.magic);
230+
resp.reserved = htons(resp.reserved);
231+
resp.nonce = htonl(resp.nonce);
232+
resp.server_id = htonll_u(resp.server_id);
233+
resp.control_port = htons(resp.control_port);
234+
resp.feedback_port = htons(resp.feedback_port);
235+
resp.proto_ver = htons(resp.proto_ver);
236+
resp.name_len = htons(resp.name_len);
237+
resp.flags = htonl(resp.flags);
238+
}
239+
181240
std::vector<uint8_t> out(sizeof(DiscoverRespV1) + name.size());
182241
std::memcpy(out.data(), &resp, sizeof(resp));
183242
if (!name.empty()) {
@@ -189,4 +248,4 @@ void DiscoveryService::runLoop() {
189248
}
190249
}
191250

192-
} // namespace lj
251+
} // namespace lj

0 commit comments

Comments
 (0)