rcon protocol helpers

This commit is contained in:
2026-02-07 22:16:10 +01:00
parent 27aa6fcd19
commit 4e0036e5f9

View File

@@ -58,9 +58,107 @@ int rcon_connect(int port) {
return sockfd;
}
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)
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);
const char null = '\0';
send(sockfd, &null, 1, 0);
}
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; }
// read body (size - 10 bytes for id, type, and two null terminators)
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) {
return -1;
}
packet->body[body_size] = '\0';
} else {
packet->body[0] = '\0';
}
return 0;
}
int rcon_authenticate(int sockfd, const char *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");
return -1;
}
if (response.id == -1) {
perror("authentication failed\n");
return -1;
}
printf("authenticated successfully\n");
return 0;
}
char* rcon_command(int sockfd, const char *command) {
static char result[8192];
result[0] = '\0';
send_packet(sockfd, 2, SERVERDATA_EXECCOMMAND, command);
// Handle multi-packet responses
while (1) {
rcon_packet_t response;
if (recv_packet(sockfd, &response) < 0) {
perror("failed to receive command response\n");
return NULL;
}
if (response.type == SERVERDATA_RESPONSE_VALUE) {
strncat(result, response.body, sizeof(result) - strlen(result) - 1);
// Check if response is complete (body length < 4096)
if (strlen(response.body) < 4096) {
break;
}
}
}
return result;
}
int main(int argc, char **argv) {
const int PORT_NUM = read_env_int("RCON_PORT_NUMBER");
const char *password = getenv("RCON_PASSWORD");
if (password == NULL) {
perror("error: RCON_PASSWORD environment variable not set.\n");
exit(EXIT_FAILURE);
}
printf("port: %d\n", PORT_NUM);
rcon_connect(PORT_NUM);
int sockfd = rcon_connect(PORT_NUM);
if (rcon_authenticate(sockfd, password) < 0) {
close(sockfd);
exit(EXIT_FAILURE);
}
// example
char *response = rcon_command(sockfd, "help");
if (response) {
printf("Response:\n%s\n", response);
}
close(sockfd);
return 0;
}