Skip to content

Commit 7544944

Browse files
committed
⬆️🐛 add client -> server message support
- was already ambiguously required by spec for potential future message types - was explicitly required by spec for experimental types - now additionall required for client hello; debugmessage are bidirrectional, and client "SHOULD" send one on connection
1 parent 7c73fe3 commit 7544944

File tree

2 files changed

+81
-10
lines changed

2 files changed

+81
-10
lines changed

include/OTDIPC/DebugMessage.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ namespace OTDIPC::inline V2::Messages {
1313
struct DebugMessage : Header {
1414
static constexpr MessageType MESSAGE_TYPE = MessageType::DebugMessage;
1515

16-
char first {};
16+
char data [1] {};
1717

18+
[[nodiscard]]
1819
std::string_view message() const
1920
{
20-
return { &first, this->size - sizeof(Header) };
21+
return { data, this->size - sizeof(Header) };
2122
}
2223
};
2324
}

src/V2Server.cpp

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "V2Server.hpp"
44

55
#include <afunix.h>
6+
#include <expected>
67
#include <shlobj.h>
78
#include <wil/filesystem.h>
89
#include <wil/result.h>
@@ -13,6 +14,8 @@
1314
#include <fstream>
1415
#include <functional>
1516
#include <iostream>
17+
#include <print>
18+
#include <variant>
1619

1720
#include <OTDIPC/DebugMessage.hpp>
1821
#include <OTDIPC/Ping.hpp>
@@ -37,6 +40,33 @@ void InitHeader(T& msg, uint32_t tabletId, std::size_t size = sizeof(T)) {
3740
msg.size = static_cast<uint32_t>(size);
3841
msg.nonPersistentTabletId = tabletId;
3942
}
43+
44+
struct socket_closed_t {};
45+
struct wsa_error_t { int value {}; };
46+
inline constexpr socket_closed_t socket_closed;
47+
48+
std::expected<void, std::variant<socket_closed_t, wsa_error_t>>
49+
ReadNBytes(SOCKET socket, void* const buffer, const std::size_t count) {
50+
auto p = buffer;
51+
auto toRead = count;
52+
while (toRead > 0) {
53+
const int result
54+
= recv(socket, static_cast<char*>(p), static_cast<int>(toRead), 0);
55+
if (result == 0) {
56+
return std::unexpected {socket_closed};
57+
}
58+
if (result == SOCKET_ERROR) {
59+
const auto error = WSAGetLastError();
60+
if (error == WSAECONNRESET) {
61+
return std::unexpected {socket_closed};
62+
}
63+
return std::unexpected {wsa_error_t { error }};
64+
}
65+
toRead -= result;
66+
}
67+
return {};
68+
}
69+
4070
}// namespace
4171

4272
V2Server::V2Server(Config config, const DefaultBehavior defaultBehavior)
@@ -164,15 +194,53 @@ void V2Server::AcceptOnce(const std::stop_token st) {
164194
// send anything, so any read > 0 is weird (protocol violation), and read == 0
165195
// means disconnect.
166196

167-
char buffer[1];
197+
std::vector<std::byte> buffer;
198+
buffer.resize(1024);
168199
while (!st.stop_requested()) {
169-
int result = recv(mClientSocket.get(), buffer, 1, 0);
170-
if (result <= 0) {
171-
// 0 = Graceful disconnect, -1 = Error
172-
break;
200+
struct ReadErrorVisitor {
201+
static void operator()(socket_closed_t) {
202+
std::println("Client has disconnected");
203+
}
204+
static void operator()(const wsa_error_t error) {
205+
std::println(
206+
stderr,
207+
"Reading from client failed with {:#010x}",
208+
static_cast<uint32_t>(HRESULT_FROM_WIN32(error.value)));
209+
}
210+
};
211+
212+
auto it = buffer.data();
213+
auto header = reinterpret_cast<OTDIPC::Messages::Header*>(buffer.data());
214+
if (const auto ok = ReadNBytes(mClientSocket.get(), it, sizeof(*header));
215+
!ok) {
216+
std::visit(ReadErrorVisitor {}, ok.error());
217+
return;
218+
}
219+
220+
if (header->size > buffer.size()) {
221+
buffer.resize(header->size);
222+
header = reinterpret_cast<OTDIPC::Messages::Header*>(buffer.data());
223+
it = buffer.data();
224+
}
225+
it += sizeof(*header);
226+
227+
if (const auto ok
228+
= ReadNBytes(mClientSocket.get(), it, header->size - sizeof(*header));
229+
!ok) {
230+
std::visit(ReadErrorVisitor {}, ok.error());
231+
return;
232+
}
233+
234+
if (header->messageType == OTDIPC::Messages::DebugMessage::MESSAGE_TYPE) {
235+
std::println(
236+
"Client message: {}",
237+
reinterpret_cast<OTDIPC::Messages::DebugMessage*>(header)->message());
238+
} else {
239+
std::println(
240+
stderr,
241+
"Received unexpected client message type {}",
242+
std::to_underlying(header->messageType));
173243
}
174-
// If client sends data, we ignore it per protocol, but keep reading to
175-
// detect disconnect.
176244
}
177245
mClientSocket.reset();
178246
}
@@ -255,7 +323,9 @@ void V2Server::SendDebugMessage(std::string_view message) {
255323

256324
std::vector<char> buffer(totalSize);
257325
InitHeader(
258-
*reinterpret_cast<OTDIPC::Messages::DebugMessage*>(buffer.data()), 0, totalSize);
326+
*reinterpret_cast<OTDIPC::Messages::DebugMessage*>(buffer.data()),
327+
0,
328+
totalSize);
259329

260330
// Copy string data immediately after header
261331
std::memcpy(

0 commit comments

Comments
 (0)