game: pull out single-client logic from XSocketServer

This commit is contained in:
Tyler Wilding
2022-05-01 16:15:26 -04:00
parent 0a74c9ad9d
commit a9f963b545
6 changed files with 97 additions and 78 deletions
+2 -36
View File
@@ -25,16 +25,8 @@ XSocketServer::~XSocketServer() {
}
void XSocketServer::shutdown_server() {
// Cleanup the accept thread
if (accept_thread_running) {
kill_accept_thread = true;
accept_thread.join();
accept_thread_running = false;
}
// Close the listening and accepted socket socket
close_server_socket();
close_socket(accepted_socket);
}
bool XSocketServer::init_server() {
@@ -83,8 +75,8 @@ bool XSocketServer::init_server() {
}
server_initialized = true;
accept_thread = std::thread(&XSocketServer::accept_thread_func, this);
fmt::print("[XSocketServer:{}] awaiting connections\n", tcp_port);
fmt::print("[XSocketServer:{}] initialized\n", tcp_port);
post_init();
return true;
}
@@ -92,29 +84,3 @@ void XSocketServer::close_server_socket() {
close_socket(listening_socket);
listening_socket = -1;
}
void XSocketServer::accept_thread_func() {
socklen_t l = sizeof(addr);
while (!kill_accept_thread) {
if (accepted_socket == -1) {
this->accepted_socket = accept_socket(listening_socket, (sockaddr*)&addr, &l);
fmt::print("Accept Socket in XSocketServer: {}\n", this->accepted_socket);
set_socket_timeout(this->accepted_socket, 100000);
write_on_accept();
client_connected = true;
}
std::this_thread::sleep_for(std::chrono::microseconds(50000));
}
}
bool XSocketServer::wait_for_connection() {
return client_connected;
}
void XSocketServer::lock() {
server_mutex.lock();
}
void XSocketServer::unlock() {
server_mutex.unlock();
}
+5 -13
View File
@@ -11,28 +11,25 @@
class XSocketServer {
public:
static constexpr int DEF_BUFFER_SIZE = 32 * 1024 * 1024;
XSocketServer(const XSocketServer&) = delete;
XSocketServer& operator=(const XSocketServer&) = delete;
XSocketServer(std::function<bool()> shutdown_callback,
int _tcp_port,
int _buffer_size = DEF_BUFFER_SIZE);
virtual ~XSocketServer();
XSocketServer(const XSocketServer&) = delete;
XSocketServer& operator=(const XSocketServer&) = delete;
bool init_server();
void shutdown_server();
void close_server_socket();
bool wait_for_connection();
void lock();
void unlock();
// Abstract methods -- use-case dependent
virtual void write_on_accept() = 0;
virtual void post_init() = 0;
protected:
int tcp_port;
struct sockaddr_in addr = {};
int listening_socket = -1;
int accepted_socket = -1;
std::vector<char> buffer;
bool kill_accept_thread = false;
@@ -41,9 +38,4 @@ class XSocketServer {
bool client_connected = false;
std::function<bool()> want_exit_callback;
std::thread accept_thread;
std::mutex server_mutex;
void accept_thread_func();
};
+1 -1
View File
@@ -93,7 +93,7 @@ void deci2_runner(SystemThreadInterface& iface) {
lg::debug("[DECI2] Waiting for listener...");
bool saw_listener = false;
while (!iface.get_want_exit()) {
if (server.wait_for_connection()) {
if (server.is_client_connected()) {
if (!saw_listener) {
lg::debug("[DECI2] Connected!");
}
+52 -5
View File
@@ -14,11 +14,46 @@
#include "third-party/fmt/core.h"
void Deci2Server::write_on_accept() {
u32 versions[2] = {versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR};
lock();
write_to_socket(accepted_socket, (char*)&versions, 8);
unlock();
#ifdef _WIN32
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#endif
Deci2Server::~Deci2Server() {
// Cleanup the accept thread
if (accept_thread_running) {
kill_accept_thread = true;
accept_thread.join();
accept_thread_running = false;
}
close_socket(accepted_socket);
}
void Deci2Server::post_init() {
fmt::print("[Deci2Server:{}] awaiting connections\n", tcp_port);
accept_thread = std::thread(&Deci2Server::accept_thread_func, this);
}
void Deci2Server::accept_thread_func() {
socklen_t addr_len = sizeof(addr);
while (!kill_accept_thread) {
if (accepted_socket == -1) {
accepted_socket = accept_socket(listening_socket, (sockaddr*)&addr, &addr_len);
set_socket_timeout(accepted_socket, 100000);
u32 versions[2] = {versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR};
write_to_socket(accepted_socket, (char*)&versions, 8);
client_connected = true;
return; // stop accepting connections
}
std::this_thread::sleep_for(std::chrono::microseconds(50000));
}
}
bool Deci2Server::is_client_connected() {
return client_connected;
}
/*!
@@ -48,6 +83,10 @@ void Deci2Server::send_proto_ready(Deci2Driver* drivers, int* driver_count) {
}
void Deci2Server::read_data() {
if (!is_client_connected()) {
return;
}
int desired_size = (int)sizeof(Deci2Header);
int got = 0;
@@ -133,3 +172,11 @@ void Deci2Server::send_data(void* buf, u16 len) {
}
unlock();
}
void Deci2Server::lock() {
server_mutex.lock();
}
void Deci2Server::unlock() {
server_mutex.unlock();
}
+15 -1
View File
@@ -10,17 +10,31 @@
class Deci2Server : public XSocketServer {
public:
using XSocketServer::XSocketServer;
virtual ~Deci2Server();
void post_init() override;
void pre_shutdown() override;
void write_on_accept() override;
void read_data();
void send_data(void* buf, u16 len);
bool is_client_connected();
void wait_for_protos_ready();
void send_proto_ready(Deci2Driver* drivers, int* driver_count);
void lock();
void unlock();
private:
bool protocols_ready = false;
std::condition_variable cv;
Deci2Driver* d2_drivers = nullptr;
int* d2_driver_count = nullptr;
int accepted_socket = -1;
std::thread accept_thread;
std::mutex server_mutex;
void accept_thread_func();
};
+22 -22
View File
@@ -40,26 +40,26 @@ TEST(Listener, ListenToNothing) {
TEST(Listener, DeciCheckNoListener) {
Deci2Server s(always_false, DECI2_PORT);
EXPECT_TRUE(s.init_server());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.is_client_connected());
EXPECT_FALSE(s.is_client_connected());
EXPECT_FALSE(s.is_client_connected());
}
TEST(Listener, CheckConnectionStaysAlive) {
Deci2Server s(always_false, DECI2_PORT);
EXPECT_TRUE(s.init_server());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.is_client_connected());
Listener l;
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.is_client_connected());
bool connected = l.connect_to_target();
EXPECT_TRUE(connected);
// TODO - some sort of backoff and retry would be better
while (connected && !s.wait_for_connection()) {
while (connected && !s.is_client_connected()) {
}
EXPECT_TRUE(s.wait_for_connection());
EXPECT_TRUE(s.is_client_connected());
std::this_thread::sleep_for(std::chrono::milliseconds(500));
EXPECT_TRUE(s.wait_for_connection());
EXPECT_TRUE(s.is_client_connected());
EXPECT_TRUE(l.is_connected());
}
@@ -67,19 +67,19 @@ TEST(Listener, DeciThenListener) {
for (int i = 0; i < 3; i++) {
Deci2Server s(always_false, DECI2_PORT);
EXPECT_TRUE(s.init_server());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.is_client_connected());
EXPECT_FALSE(s.is_client_connected());
EXPECT_FALSE(s.is_client_connected());
Listener l;
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.is_client_connected());
EXPECT_FALSE(s.is_client_connected());
bool connected = l.connect_to_target();
EXPECT_TRUE(connected);
// TODO - some sort of backoff and retry would be better
while (connected && !s.wait_for_connection()) {
while (connected && !s.is_client_connected()) {
}
EXPECT_TRUE(s.wait_for_connection());
EXPECT_TRUE(s.is_client_connected());
}
}
@@ -87,12 +87,12 @@ TEST(Listener, DeciThenListener2) {
for (int i = 0; i < 3; i++) {
Deci2Server s(always_false, DECI2_PORT);
EXPECT_TRUE(s.init_server());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.is_client_connected());
EXPECT_FALSE(s.is_client_connected());
EXPECT_FALSE(s.is_client_connected());
Listener l;
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.is_client_connected());
EXPECT_FALSE(s.is_client_connected());
EXPECT_TRUE(l.connect_to_target());
}
}
@@ -103,11 +103,11 @@ TEST(Listener, ListenerThenDeci) {
EXPECT_FALSE(l.connect_to_target());
Deci2Server s(always_false, DECI2_PORT);
EXPECT_TRUE(s.init_server());
EXPECT_FALSE(s.wait_for_connection());
EXPECT_FALSE(s.is_client_connected());
bool connected = l.connect_to_target();
EXPECT_TRUE(connected);
// TODO - some sort of backoff and retry would be better
while (connected && !s.wait_for_connection()) {
while (connected && !s.is_client_connected()) {
}
}
}