more error handling

This commit is contained in:
2026-02-07 23:18:57 +01:00
parent 366405c82a
commit ac67ea4f7f

View File

@@ -6,6 +6,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdint.h>
#include <errno.h>
const char *LOCALHOST = "127.0.0.1";
@@ -47,7 +48,12 @@ int rcon_connect(int port) {
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
inet_pton(AF_INET, LOCALHOST, &server_addr.sin_addr);
if (inet_pton(AF_INET, LOCALHOST, &server_addr.sin_addr) <= 0) {
perror("invalid address");
close(sockfd);
exit(EXIT_FAILURE);
}
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("connection failed");
@@ -61,24 +67,68 @@ int rcon_connect(int port) {
void send_packet(int sockfd, int32_t id, int32_t type, const char *body) {
int body_len = strlen(body);
int32_t size = 10 + body_len; // 4 (id) + 4 (type) + body + 2 (null terminators)
int32_t size = 10 + body_len;
send(sockfd, &size, sizeof(int32_t), 0);
send(sockfd, &id, sizeof(int32_t), 0);
send(sockfd, &type, sizeof(int32_t), 0);
send(sockfd, body, body_len + 1, 0);
printf("DEBUG: sending packet - id=%d, type=%d, size=%d, body='%s'\n",
id, type, size, body);
if (send(sockfd, &size, sizeof(int32_t), 0) < 0) {
perror("send size failed");
return;
}
if (send(sockfd, &id, sizeof(int32_t), 0) < 0) {
perror("send id failed");
return;
}
if (send(sockfd, &type, sizeof(int32_t), 0) < 0) {
perror("send type failed");
return;
}
if (send(sockfd, body, body_len + 1, 0) < 0) {
perror("send body failed");
return;
}
const char null = '\0';
send(sockfd, &null, 1, 0);
if (send(sockfd, &null, 1, 0) < 0) {
perror("send null failed");
return;
}
printf("DEBUG: packet sent successfully\n");
}
int recv_packet(int sockfd, rcon_packet_t *packet) {
if (recv(sockfd, &packet->size, sizeof(int32_t), 0) <= 0) { return -1; }
if (recv(sockfd, &packet->id, sizeof(int32_t), 0) <= 0) { return -1; }
if (recv(sockfd, &packet->type, sizeof(int32_t), 0) <= 0) { return -1; }
ssize_t bytes;
bytes = recv(sockfd, &packet->size, sizeof(int32_t), 0);
if (bytes <= 0) {
if (bytes == 0) {
fprintf(stderr, "connection closed by server (no data received)\n");
} else {
perror("recv size failed");
}
return -1;
}
printf("DEBUG: received size=%d\n", packet->size);
bytes = recv(sockfd, &packet->id, sizeof(int32_t), 0);
if (bytes <= 0) {
perror("recv id failed");
return -1;
}
bytes = recv(sockfd, &packet->type, sizeof(int32_t), 0);
if (bytes <= 0) {
perror("recv type failed");
return -1;
}
int body_size = packet->size - 10;
if (body_size > 0 && body_size < sizeof(packet->body)) {
if (recv(sockfd, packet->body, body_size + 2, 0) <= 0) {
if (body_size > 0 && body_size < (int)sizeof(packet->body)) {
bytes = recv(sockfd, packet->body, body_size + 2, 0);
if (bytes <= 0) {
perror("recv body failed");
return -1;
}
packet->body[body_size] = '\0';
@@ -86,20 +136,34 @@ int recv_packet(int sockfd, rcon_packet_t *packet) {
packet->body[0] = '\0';
}
printf("DEBUG: received packet - id=%d, type=%d, body='%s'\n",
packet->id, packet->type, packet->body);
return 0;
}
int rcon_authenticate(int sockfd, const char *password) {
printf("authenticating with password: '%s' (length=%zu)\n",
password, strlen(password));
send_packet(sockfd, 1, SERVERDATA_AUTH, password);
rcon_packet_t response;
if (recv_packet(sockfd, &response) < 0) {
perror("failed to receive auth response\n");
printf("waiting for auth responses...\n");
rcon_packet_t response1;
if (recv_packet(sockfd, &response1) < 0) {
fprintf(stderr, "failed to receive first auth response\n");
return -1;
}
if (response.id == -1) {
perror("authentication failed\n");
rcon_packet_t response2;
if (recv_packet(sockfd, &response2) < 0) {
fprintf(stderr, "failed to receive second auth response\n");
return -1;
}
if (response2.id == -1) {
fprintf(stderr, "authentication failed - invalid password\n");
return -1;
}
@@ -117,11 +181,10 @@ char* rcon_command_multipacket(int sockfd, const char *command) {
send_packet(sockfd, cmd_id, SERVERDATA_EXECCOMMAND, command);
send_packet(sockfd, dummy_id, SERVERDATA_EXECCOMMAND, "");
// read packets until we get the dummy response
while (1) {
rcon_packet_t response;
if (recv_packet(sockfd, &response) < 0) {
perror("failed to receive command response\n");
fprintf(stderr, "failed to receive command response\n");
return NULL;
}
if (response.id == dummy_id) {
@@ -140,11 +203,15 @@ int main(int argc, char **argv) {
const char *password = getenv("RCON_PASSWORD");
if (password == NULL) {
perror("error: RCON_PASSWORD environment variable not set.\n");
fprintf(stderr, "error: RCON_PASSWORD environment variable not set.\n");
exit(EXIT_FAILURE);
}
printf("=== RCON Configuration ===\n");
printf("port: %d\n", PORT_NUM);
printf("password: '%s'\n", password);
printf("password length: %zu bytes\n", strlen(password));
printf("==========================\n\n");
int sockfd = rcon_connect(PORT_NUM);
@@ -154,13 +221,14 @@ int main(int argc, char **argv) {
}
const char *get_player_positions_cmd = "execute as @a run data get entity @s Pos";
printf("\nexecuting command: %s\n", get_player_positions_cmd);
char *response = rcon_command_multipacket(sockfd, get_player_positions_cmd);
if (response) {
printf("\n=== player positions ===\n");
printf("%s\n", response);
} else {
perror("failed to get player positions\n");
fprintf(stderr, "failed to get player positions\n");
}
close(sockfd);