Skip to content
This repository was archived by the owner on Mar 29, 2026. It is now read-only.

Commit 76ba2f3

Browse files
committed
fix: send/recv now uses MSG_NOSIGNAL, improved server logging, changed disconnect logic from heartbeat
1 parent 5dbab0f commit 76ba2f3

5 files changed

Lines changed: 73 additions & 26 deletions

File tree

include/rconpp/server.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ struct connected_client {
2929

3030
bool authenticated{false};
3131

32+
bool force_disconnect{false};
33+
3234
time_t last_heartbeat{0};
3335
};
3436

include/rconpp/utilities.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ constexpr int MIN_PACKET_LENGTH = 14;
1616
constexpr int MAX_RETRIES_TO_RECEIVE_INFO = 500;
1717
constexpr int HEARTBEAT_TIME = 30;
1818

19+
#ifndef MSG_NOSIGNAL
20+
#define MSG_NOSIGNAL 0
21+
#endif
22+
1923

2024
enum data_type {
2125
/**
@@ -62,6 +66,12 @@ struct response {
6266
bool server_responded{false};
6367
};
6468

69+
enum error_type {
70+
DISCONNECTED = 0,
71+
BAD_FD = 1,
72+
SHUTTING_DOWN = 2,
73+
};
74+
6575
/**
6676
* @brief Form a valid RCON packet.
6777
*
@@ -92,9 +102,9 @@ RCONPP_EXPORT int bit32_to_int(const std::vector<char>& buffer);
92102
RCONPP_EXPORT int type_to_int(const std::vector<char>& buffer);
93103

94104
/**
95-
* @brief Reports the recent socket error.
105+
* @brief Converts the last error into error_type and reports it.
96106
*/
97-
RCONPP_EXPORT void report_error();
107+
RCONPP_EXPORT error_type report_get_last_error();
98108

99109
/**
100110
* @brief Reads the first 4 bytes of a packet to get the packet size (not to be mistaken with length).

src/rconpp/client.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ rconpp::response rconpp::rcon_client::send_data_sync(const std::string_view data
3434

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

37-
if (send(sock, formed_packet.data.data(), formed_packet.length, 0) < 0) {
37+
if (send(sock, formed_packet.data.data(), formed_packet.length, MSG_NOSIGNAL) < 0) {
3838
on_log("Sending failed!");
39-
report_error();
39+
report_get_last_error();
4040
return { "", false };
4141
}
4242

@@ -69,7 +69,7 @@ bool rconpp::rcon_client::connect_to_server() {
6969
if (sock == -1) {
7070
#endif
7171
on_log("Failed to open socket.");
72-
report_error();
72+
report_get_last_error();
7373
return false;
7474
}
7575

@@ -104,7 +104,7 @@ bool rconpp::rcon_client::connect_to_server() {
104104
int status = connect(sock, (struct sockaddr*)&server, sizeof(server));
105105

106106
if (status == -1) {
107-
report_error();
107+
report_get_last_error();
108108
return false;
109109
}
110110

@@ -178,7 +178,7 @@ rconpp::packet rconpp::rcon_client::read_packet() {
178178
* Receiving by the length of the packet will give us 4 extra bytes, so, we do by size here.
179179
* This is because read_packet_size() reads the first 4 bytes and discards them.
180180
*/
181-
recv(sock, buffer.data(), temp_packet.size, 0);
181+
recv(sock, buffer.data(), temp_packet.size, MSG_NOSIGNAL);
182182

183183
temp_packet.data = buffer;
184184

src/rconpp/server.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ bool rconpp::rcon_server::startup_server() {
5555
if (sock == -1) {
5656
#endif
5757
on_log("Failed to open socket.");
58-
report_error();
58+
report_get_last_error();
5959
return false;
6060
}
6161

@@ -73,14 +73,14 @@ bool rconpp::rcon_server::startup_server() {
7373
int status = bind(sock, reinterpret_cast<const sockaddr*>(&server), sizeof(server));
7474

7575
if (status == -1) {
76-
report_error();
76+
report_get_last_error();
7777
return false;
7878
}
7979

8080
status = listen(sock, SOMAXCONN);
8181

8282
if (status == -1) {
83-
report_error();
83+
report_get_last_error();
8484
return false;
8585
}
8686

@@ -119,7 +119,7 @@ void rconpp::rcon_server::disconnect_client(const int client_socket, const bool
119119
}
120120

121121
void rconpp::rcon_server::read_packet(connected_client& client) {
122-
const int packet_size = read_packet_size(static_cast<int>(client.socket));
122+
const int packet_size = read_packet_size(client.socket);
123123

124124
// Silently ignore packet size.
125125
if (packet_size < MIN_PACKET_SIZE) {
@@ -129,9 +129,9 @@ void rconpp::rcon_server::read_packet(connected_client& client) {
129129
std::vector<char> buffer{};
130130
buffer.resize(packet_size);
131131

132-
if (recv(client.socket, buffer.data(), packet_size, 0) == -1) {
132+
if (recv(client.socket, buffer.data(), packet_size, MSG_NOSIGNAL) == -1) {
133133
on_log("Failed to get a packet from client.");
134-
report_error();
134+
report_get_last_error();
135135
return;
136136
}
137137

@@ -149,8 +149,10 @@ void rconpp::rcon_server::read_packet(connected_client& client) {
149149
if (packet_data == password) {
150150
packet_to_send = form_packet("", id, SERVERDATA_AUTH_RESPONSE);
151151
client.authenticated = true;
152+
on_log("Client [" + std::string(inet_ntoa(client.sock_info.sin_addr)) + ":" + std::to_string(ntohs(client.sock_info.sin_port)) + "] has authenticated successfully!");
152153
} else {
153154
packet_to_send = form_packet("", -1, SERVERDATA_AUTH_RESPONSE);
155+
on_log("Client [" + std::string(inet_ntoa(client.sock_info.sin_addr)) + ":" + std::to_string(ntohs(client.sock_info.sin_port)) + "] failed authentication!");
154156
}
155157
} else {
156158
if (type != SERVERDATA_EXECCOMMAND) {
@@ -184,9 +186,9 @@ void rconpp::rcon_server::read_packet(connected_client& client) {
184186

185187
on_log("Sending packet (of size: " + std::to_string(packet_to_send.length) + ") to client [" + std::string(inet_ntoa(client.sock_info.sin_addr)) + ":" + std::to_string(ntohs(client.sock_info.sin_port)) + "]");
186188

187-
if (send(client.socket, packet_to_send.data.data(), packet_to_send.length, 0) < 0) {
189+
if (send(client.socket, packet_to_send.data.data(), packet_to_send.length, MSG_NOSIGNAL) < 0) {
188190
on_log("Sending failed!");
189-
report_error();
191+
report_get_last_error();
190192
return;
191193
}
192194
}
@@ -195,9 +197,9 @@ bool rconpp::rcon_server::send_heartbeat(connected_client& client) {
195197
on_log("Sending heartbeat to client [" + std::string(inet_ntoa(client.sock_info.sin_addr)) + ":" + std::to_string(ntohs(client.sock_info.sin_port)) + "]");
196198

197199
packet packet_to_send = form_packet("", -1, SERVERDATA_RESPONSE_VALUE);
198-
if (send(client.socket, packet_to_send.data.data(), packet_to_send.length, 0) < 0) {
200+
if (send(client.socket, packet_to_send.data.data(), packet_to_send.length, MSG_NOSIGNAL) < 0) {
199201
on_log("Failed to send a heartbeat to client [" + std::string(inet_ntoa(client.sock_info.sin_addr)) + ":" + std::to_string(ntohs(client.sock_info.sin_port)) + "]");
200-
report_error();
202+
report_get_last_error();
201203
return false;
202204
}
203205

@@ -238,11 +240,11 @@ void rconpp::rcon_server::start(bool return_after) {
238240

239241
if (client_socket == -1) {
240242
on_log("client with socket: \"" + std::to_string(client_socket) + "\" failed to connect.");
241-
report_error();
243+
report_get_last_error();
242244
continue;
243245
}
244246

245-
on_log("Client [" + std::string(inet_ntoa(client_info.sin_addr)) + ":" + std::to_string(ntohs(client_info.sin_port)) + "] has connected to the server.");
247+
on_log("Client [" + std::string(inet_ntoa(client_info.sin_addr)) + ":" + std::to_string(ntohs(client_info.sin_port)) + "] has connected to the server, asking for authentication.");
246248

247249
connected_client client{};
248250

@@ -260,12 +262,16 @@ void rconpp::rcon_server::start(bool return_after) {
260262
if (client.last_heartbeat == 0 || current_time - client.last_heartbeat >= HEARTBEAT_TIME)
261263
{
262264
if (!send_heartbeat(client)) {
263-
disconnect_client(client.socket);
264-
return;
265+
client.force_disconnect = true;
265266
}
266267
}
267268
}
268269

270+
if (client.force_disconnect) {
271+
disconnect_client(client.socket);
272+
return;
273+
}
274+
269275
// No need to let the server keep running this causing 100% usage on a thread, we can wait a bit between requests.
270276
std::this_thread::sleep_for(std::chrono::milliseconds(100));
271277
}

src/rconpp/utilities.cpp

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,41 @@ int rconpp::type_to_int(const std::vector<char>& buffer) {
3838
return static_cast<int>(buffer[4] | buffer[5] << 8 | buffer[6] << 16 | buffer[7] << 24);
3939
}
4040

41-
void rconpp::report_error() {
41+
rconpp::error_type rconpp::report_get_last_error() {
42+
error_type current_error;
43+
44+
int last_error{-1};
45+
4246
#ifdef _WIN32
43-
std::cout << "Error code: " << WSAGetLastError() << "\n";
47+
last_error = WSAGetLastError();
4448
#else
45-
std::cout << "Error code: " << errno << "\n";
49+
last_error = errno;
50+
#endif;
51+
52+
std::cout << "Error code: " << last_error << "\n";
53+
54+
#ifdef _WIN32
55+
switch (last_error) {
56+
default:
57+
case WSAECONNRESET:
58+
current_error = DISCONNECTED;
59+
break;
60+
case WSAEINTR:
61+
current_error = SHUTTING_DOWN;
62+
break;
63+
}
64+
#else
65+
switch (last_error) {
66+
default:
67+
case 32:
68+
case 104:
69+
current_error = DISCONNECTED;
70+
break;
71+
case:
72+
}
4673
#endif
74+
75+
return current_error;
4776
}
4877

4978
int rconpp::read_packet_size(int socket) {
@@ -54,8 +83,8 @@ int rconpp::read_packet_size(int socket) {
5483
* RCON gives the packet SIZE in the first four (4) bytes of each packet.
5584
* We simply just want to read that and then return it.
5685
*/
57-
if (recv(socket, buffer.data(), 4, 0) == -1) {
58-
report_error();
86+
if (recv(socket, buffer.data(), 4, MSG_NOSIGNAL) == -1) {
87+
report_get_last_error();
5988
return -1;
6089
}
6190

0 commit comments

Comments
 (0)