Files
Shipwright/soh/soh/Network/Network.cpp
T
Philip Dubé b61db77020 more hardening of code in Network/ (#6650)
also unique_ptr
2026-06-05 06:16:11 +00:00

166 lines
4.7 KiB
C++

#include "Network.h"
#include <spdlog/spdlog.h>
#include <libultraship/libultraship.h>
// MARK: - Public
void Network::Enable(const char* host, uint16_t port) {
#ifdef ENABLE_REMOTE_CONTROL
if (isEnabled) {
return;
}
if (SDLNet_ResolveHost(&networkAddress, host, port) == -1) {
SPDLOG_ERROR("[Network] SDLNet_ResolveHost: {}", SDLNet_GetError());
}
isEnabled = true;
// First check if there is a thread running, if so, join it
if (receiveThread.joinable()) {
receiveThread.join();
}
receiveThread = std::thread(&Network::ReceiveFromServer, this);
#endif
}
void Network::Disable() {
if (!isEnabled) {
return;
}
isEnabled = false;
receiveThread.join();
}
void Network::OnIncomingData(char payload[512]) {
}
void Network::OnIncomingJson(nlohmann::json payload) {
}
void Network::OnConnected() {
}
void Network::OnDisconnected() {
}
void Network::ProcessOutgoingPackets() {
}
void Network::SendDataToRemote(const char* payload) {
#ifdef ENABLE_REMOTE_CONTROL
SPDLOG_DEBUG("[Network] Sending data: {}", payload);
SDLNet_TCP_Send(networkSocket, payload, strlen(payload) + 1);
#endif
}
void Network::SendJsonToRemote(nlohmann::json payload) {
SendDataToRemote(payload.dump().c_str());
}
// MARK: - Private
void Network::ReceiveFromServer() {
#ifdef ENABLE_REMOTE_CONTROL
while (isEnabled) {
while (!isConnected && isEnabled) {
SPDLOG_TRACE("[Network] Attempting to make connection to server...");
networkSocket = SDLNet_TCP_Open(&networkAddress);
if (networkSocket) {
isConnected = true;
receivedData.clear();
SPDLOG_INFO("[Network] Connection to server established!");
OnConnected();
break;
}
}
SDLNet_SocketSet socketSet = SDLNet_AllocSocketSet(1);
if (networkSocket) {
SDLNet_TCP_AddSocket(socketSet, networkSocket);
}
// Listen to socket messages
while (isConnected && networkSocket && isEnabled) {
// we check first if socket has data, to not block in the TCP_Recv
int socketsReady = SDLNet_CheckSockets(socketSet, 0);
if (socketsReady == -1) {
SPDLOG_ERROR("[Network] SDLNet_CheckSockets: {}", SDLNet_GetError());
break;
}
// Always process outgoing packets
ProcessOutgoingPackets();
if (socketsReady == 0) {
// No incoming data
continue;
}
char remoteDataReceived[512];
memset(remoteDataReceived, 0, sizeof(remoteDataReceived));
int len = SDLNet_TCP_Recv(networkSocket, &remoteDataReceived, sizeof(remoteDataReceived));
if (!len || !networkSocket || len == -1) {
SPDLOG_ERROR("[Network] SDLNet_TCP_Recv: {}", SDLNet_GetError());
break;
}
HandleRemoteData(remoteDataReceived);
receivedData.append(remoteDataReceived, len);
// Proess all complete packets
size_t delimiterPos = receivedData.find('\0');
while (delimiterPos != std::string::npos) {
// Extract the complete packet until the delimiter
std::string packet = receivedData.substr(0, delimiterPos);
// Remove the packet (including the delimiter) from the received data
receivedData.erase(0, delimiterPos + 1);
HandleRemoteJson(packet);
// Find the next delimiter
delimiterPos = receivedData.find('\0');
}
}
if (socketSet) {
SDLNet_FreeSocketSet(socketSet);
}
if (isConnected) {
SDLNet_TCP_Close(networkSocket);
networkSocket = nullptr;
isConnected = false;
receivedData.clear();
OnDisconnected();
SPDLOG_INFO("[Network] Ending receiving thread...");
}
}
#endif
}
void Network::HandleRemoteData(char payload[512]) {
OnIncomingData(payload);
}
void Network::HandleRemoteJson(std::string payload) {
SPDLOG_DEBUG("[Network] Received json: {}", payload);
nlohmann::json jsonPayload;
try {
jsonPayload = nlohmann::json::parse(payload);
} catch (const std::exception& e) {
SPDLOG_ERROR("[Network] Failed to parse json: \n{}\n{}\n", payload, e.what());
return;
}
try {
OnIncomingJson(jsonPayload);
} catch (const std::exception& e) {
SPDLOG_ERROR("[Network] Exception handling incoming JSON: {}", e.what());
} catch (...) { SPDLOG_ERROR("[Network] Unknown exception handling incoming JSON"); }
}