more error handling
This commit is contained in:
110
src/main.c
110
src/main.c
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user