Skip to content

Commit

Permalink
feat: added custom logging, changed how servers/clients start
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaskowicz1 committed Jan 9, 2024
1 parent 5e18ca7 commit dd9737d
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 132 deletions.
9 changes: 8 additions & 1 deletion include/rconpp/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <iostream>
#include <cstring>
#include <thread>
#include <condition_variable>
#include "utilities.h"

namespace rconpp {
Expand Down Expand Up @@ -45,8 +46,12 @@ class RCONPP_EXPORT rcon_client {
public:
bool connected{false};

std::function<void(const std::string_view& log)> on_log;

std::condition_variable terminating;

/**
* @brief rcon constuctor. Initiates a connection to an RCON server with the parameters given.
* @brief rcon_client constuctor.
*
* @param addr The IP Address (NOT domain) to connect to.
* @param _port The port to connect to.
Expand All @@ -59,6 +64,8 @@ class RCONPP_EXPORT rcon_client {

~rcon_client();

void start(bool return_after);

/**
* @brief Send data to the connected RCON server. Requests from this function are added to a queue (`requests_queued`) and are handled by a different thread.
*
Expand Down
19 changes: 11 additions & 8 deletions include/rconpp/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <iostream>
#include <cstring>
#include <thread>
#include <condition_variable>
#include "utilities.h"

namespace rconpp {
Expand All @@ -29,19 +30,15 @@ struct connected_client {
bool authenticated{false};
};

struct server_info {
std::string address{};
int port{0};
std::string password{};
};

struct client_command {
connected_client client;
std::string command{};
};

class RCONPP_EXPORT rcon_server {
server_info serv_info{};
std::string address{};
int port{0};
std::string password{};

#ifdef _WIN32
SOCKET sock{INVALID_SOCKET};
Expand All @@ -56,6 +53,10 @@ class RCONPP_EXPORT rcon_server {

std::function<std::string(const client_command& command)> on_command;

std::function<void(const std::string_view log)> on_log = {};

std::condition_variable terminating;

/**
* @brief A map of connected clients. The key is their socket to talk to.
*/
Expand All @@ -73,10 +74,12 @@ class RCONPP_EXPORT rcon_server {
* @note This is a blocking call (done on purpose). It needs to wait to connect to the RCON server before anything else happens.
* It will timeout after 4 seconds if it can't connect.
*/
rcon_server(const std::string_view addr, const int port, const std::string_view pass);
rcon_server(const std::string_view addr, const int _port, const std::string_view pass);

~rcon_server();

void start(bool return_after);

/**
* @brief Disconnect a client from the server.
*
Expand Down
118 changes: 67 additions & 51 deletions src/rconpp/client.cpp
Original file line number Diff line number Diff line change
@@ -1,59 +1,16 @@
#include <mutex>
#include "client.h"
#include "utilities.h"

rconpp::rcon_client::rcon_client(const std::string_view addr, const int _port, const std::string_view pass) : address(addr), port(_port), password(pass) {

if(_port > 65535) {
std::cout << "Invalid port! The port can't exceed 65535!" << "\n";
return;
}

std::cout << "Attempting connection to RCON server..." << "\n";

if (!connect_to_server()) {
std::cout << "RCON is aborting as it failed to initiate client." << "\n";
return;
}

std::cout << "Connected successfully! Sending login data..." << "\n";

// The server will send SERVERDATA_AUTH_RESPONSE once it's happy. If it's not -1, the server will have accepted us!
response response = send_data_sync(pass, 1, data_type::SERVERDATA_AUTH, true);

if (!response.server_responded) {
std::cout << "Login data was incorrect. RCON will now abort." << "\n";
return;
}

std::cout << "Sent login data." << "\n";

connected = true;

queue_runner = std::thread([this]() {
while (connected) {
if (requests_queued.empty()) {
continue;
}

for (const queued_request& request : requests_queued) {
// Send data to callback if it's been set.
if (request.callback)
request.callback(send_data_sync(request.data, request.id, request.type));
else
send_data_sync(request.data, request.id, request.type, false);
}

requests_queued.clear();
}
});

queue_runner.detach();
}

rconpp::rcon_client::~rcon_client() {
// Set connected to false, meaning no requests can be attempted during shutdown.
connected = false;

terminating.notify_all();

#ifdef _WIN32
closesocket(sock);
WSACleanup();
Expand All @@ -68,14 +25,14 @@ rconpp::rcon_client::~rcon_client() {

rconpp::response rconpp::rcon_client::send_data_sync(const std::string_view data, const int32_t id, rconpp::data_type type, bool feedback) {
if (!connected && type != data_type::SERVERDATA_AUTH) {
std::cout << "Cannot send data when not connected." << "\n";
on_log("Cannot send data when not connected.");
return { "", false };
}

packet formed_packet = form_packet(data, id, type);

if (send(sock, formed_packet.data.data(), formed_packet.length, 0) < 0) {
std::cout << "Sending failed!" << "\n";
on_log("Sending failed!");
report_error();
return { "", false };
}
Expand All @@ -95,7 +52,7 @@ bool rconpp::rcon_client::connect_to_server() {
WSADATA wsa_data;
int result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (result != 0) {
std::cout << "WSAStartup failed. Error: " << result << std::endl;
on_log("WSAStartup failed. Error: " + std::to_string(result));
return false;
}
#endif
Expand All @@ -108,7 +65,7 @@ bool rconpp::rcon_client::connect_to_server() {
#else
if (sock == -1) {
#endif
std::cout << "Failed to open socket." << "\n";
on_log("Failed to open socket.");
report_error();
return false;
}
Expand Down Expand Up @@ -235,10 +192,69 @@ int rconpp::rcon_client::read_packet_size() {
* We simply just want to read that and then return it.
*/
if (recv(sock, buffer.data(), 4, 0) == -1) {
std::cout << "Did not receive a packet in time. Did the server send a response?" << "\n";
on_log("Did not receive a packet in time. Did the server send a response?");
report_error();
return -1;
}

return bit32_to_int(buffer);
}

void rconpp::rcon_client::start(bool return_after) {

auto block_calling_thread = [this]() {
std::mutex thread_mutex;
std::unique_lock thread_lock(thread_mutex);
this->terminating.wait(thread_lock);
};

if(port > 65535) {
on_log("Invalid port! The port can't exceed 65535!");
return;
}

on_log("Attempting connection to RCON server...");

if (!connect_to_server()) {
on_log("RCON is aborting as it failed to initiate client.");
return;
}

on_log("Connected successfully! Sending login data...");

// The server will send SERVERDATA_AUTH_RESPONSE once it's happy. If it's not -1, the server will have accepted us!
response response = send_data_sync(password, 1, data_type::SERVERDATA_AUTH, true);

if (!response.server_responded) {
on_log("Login data was incorrect. RCON will now abort.");
return;
}

on_log("Sent login data.");

connected = true;

queue_runner = std::thread([this]() {
while (connected) {
if (requests_queued.empty()) {
continue;
}

for (const queued_request& request : requests_queued) {
// Send data to callback if it's been set.
if (request.callback)
request.callback(send_data_sync(request.data, request.id, request.type));
else
send_data_sync(request.data, request.id, request.type, false);
}

requests_queued.clear();
}
});

queue_runner.detach();

if(!return_after) {
block_calling_thread();
}
};
Loading

0 comments on commit dd9737d

Please sign in to comment.